1 /****************************************************************************
5 * cfdisk is a curses based disk drive partitioning program that can
6 * create partitions for a wide variety of operating systems including
7 * Linux, MS-DOS and OS/2.
9 * cfdisk was inspired by the fdisk program, by A. V. Le Blanc
10 * (LeBlanc@mcc.ac.uk).
12 * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu)
14 * cfdisk is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * cfdisk is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with cfdisk; if not, write to the Free Software Foundation,
26 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu
29 * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu
30 * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto
31 * <jtklehto@stekt.oulu.fi>
32 * Versions 0.8e-p: aeb@cwi.nl
33 * Rebaptised 2.9p, following util-linux versioning.
35 * Recognition of NTFS / HPFS difference inspired by patches
36 * from Marty Leisner <leisner@sdsp.mc.xerox.com>
37 * Exit codes by Enrique Zanardi <ezanardi@ull.es>:
39 * 1: command line error, out of memory
40 * 2: hardware problems [Cannot open/seek/read/write disk drive].
41 * 3: ioctl(fd, HDIO_GETGEO,...) failed. (Probably it is not a disk.)
42 * 4: bad partition table on disk. [Bad primary/logical partition].
44 * Sat, 23 Jan 1999 19:34:45 +0100 <Vincent.Renardias@ldsol.com>
45 * Internationalized + provided initial French translation.
46 * Sat Mar 20 09:26:34 EST 1999 <acme@conectiva.com.br>
48 * Sun Jul 18 03:19:42 MEST 1999 <aeb@cwi.nl>
49 * Terabyte-sized disks.
50 * Sat Jun 30 05:23:19 EST 2001 <nathans@sgi.com>
51 * XFS label recognition.
52 * Thu Nov 22 15:42:56 CET 2001 <flavio.stanchina@tin.it>
53 * ext3 and ReiserFS recognition.
55 ****************************************************************************/
78 #include <sys/ioctl.h>
79 #include <linux/types.h>
85 extern long long ext2_llseek(unsigned int fd
, long long offset
,
88 #define VERSION UTIL_LINUX_VERSION
90 #define DEFAULT_DEVICE "/dev/hda"
91 #define ALTERNATE_DEVICE "/dev/sda"
93 /* With K=1024 we have `binary' megabytes, gigabytes, etc.
94 Some misguided hackers like that.
95 With K=1000 we have MB and GB that follow the standards
96 [SI, ATA, IEEE etc] and the disk manufacturers and the law. */
99 #define LINE_LENGTH 80
100 #define MAXIMUM_PARTS 60
102 #define SECTOR_SIZE 512
104 #define MAX_HEADS 255
105 #define MAX_SECTORS 63
107 #define ACTIVE_FLAG 0x80
108 #define PART_TABLE_FLAG0 0x55
109 #define PART_TABLE_FLAG1 0xAA
112 #define FREE_SPACE 0x00
113 #define DOS_EXTENDED 0x05
114 #define OS2_OR_NTFS 0x07
115 #define WIN98_EXTENDED 0x0f
116 #define LINUX_EXTENDED 0x85
117 #define LINUX_MINIX 0x81
118 #define LINUX_SWAP 0x82
121 /* There used to be defined error messages here. However, it turns out
122 * that gettext cannot handle constructions like
124 * #define ADD_EXISTS _("This partition is already in use")
126 * print_warning(ADD_EXISTS);
128 * So, now the messages are spread over the source again.
129 * Another thing which gettext cannot cope with are multi-line strings:
134 * Print partition table:
135 * cfdisk -P{r|s|t} device
138 * (This is a commonly used gnu extension of the C syntax, but not ANSI-C.)
139 * Another reason to uglify the source a little.
143 #define PRI_OR_LOG -1
147 #define COL_ID_WIDTH 25
154 #define REDRAWKEY '\014' /* ^L */
155 #define UPKEY '\020' /* ^P */
156 #define DOWNKEY '\016' /* ^N */
164 #define GS_DEFAULT -1
167 #define PRINT_RAW_TABLE 1
168 #define PRINT_SECTOR_TABLE 2
169 #define PRINT_PARTITION_TABLE 4
171 #define IS_PRIMARY(p) ((p) >= 0 && (p) < 4)
172 #define IS_LOGICAL(p) ((p) > 3)
174 #define round_int(d) ((double)((int)(d+0.5)))
175 #define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d)))
178 unsigned char boot_ind
; /* 0x80 - active */
179 unsigned char head
; /* starting head */
180 unsigned char sector
; /* starting sector */
181 unsigned char cyl
; /* starting cylinder */
182 unsigned char sys_ind
; /* What partition type */
183 unsigned char end_head
; /* end head */
184 unsigned char end_sector
; /* end sector */
185 unsigned char end_cyl
; /* end cylinder */
186 unsigned char start4
[4]; /* starting sector counting from 0 */
187 unsigned char size4
[4]; /* nr of sectors in partition */
192 long long cylinders
= 0;
193 int cylinder_size
= 0; /* heads * sectors */
194 long long total_size
= 0; /* actual_size rounded down */
195 long long actual_size
= 0; /* set using ioctl */
196 /* explicitly given user values */
197 int user_heads
= 0, user_sectors
= 0;
198 long long user_cylinders
= 0;
199 /* kernel values; ignore the cylinders */
200 int kern_heads
= 0, kern_sectors
= 0;
201 /* partition-table derived values */
202 int pt_heads
= 0, pt_sectors
= 0;
206 set_hsc0(unsigned char *h
, unsigned char *s
, int *c
, long long sector
) {
207 if (sector
>= 1024*cylinder_size
)
208 sector
= 1024*cylinder_size
- 1;
209 *s
= sector
% sectors
+ 1;
217 set_hsc(unsigned char *h
, unsigned char *s
, unsigned char *c
,
221 set_hsc0(h
, s
, &cc
, sector
);
223 *s
|= (cc
>> 2) & 0xC0;
227 set_hsc_begin(struct partition
*p
, long long sector
) {
228 set_hsc(& p
->head
, & p
->sector
, & p
->cyl
, sector
);
232 set_hsc_end(struct partition
*p
, long long sector
) {
233 set_hsc(& p
->end_head
, & p
->end_sector
, & p
->end_cyl
, sector
);
236 #define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \
237 (x) == LINUX_EXTENDED)
239 #define is_dos_partition(x) ((x) == 1 || (x) == 4 || (x) == 6)
240 #define may_have_dos_label(x) (is_dos_partition(x) \
241 || (x) == 7 || (x) == 0xb || (x) == 0xc || (x) == 0xe \
242 || (x) == 0x11 || (x) == 0x14 || (x) == 0x16 || (x) == 0x17)
244 /* start_sect and nr_sects are stored little endian on all machines */
245 /* moreover, they are not aligned correctly */
247 store4_little_endian(unsigned char *cp
, unsigned int val
) {
248 cp
[0] = (val
& 0xff);
249 cp
[1] = ((val
>> 8) & 0xff);
250 cp
[2] = ((val
>> 16) & 0xff);
251 cp
[3] = ((val
>> 24) & 0xff);
255 read4_little_endian(unsigned char *cp
) {
256 return (unsigned int)(cp
[0]) + ((unsigned int)(cp
[1]) << 8)
257 + ((unsigned int)(cp
[2]) << 16)
258 + ((unsigned int)(cp
[3]) << 24);
262 set_start_sect(struct partition
*p
, unsigned int start_sect
) {
263 store4_little_endian(p
->start4
, start_sect
);
267 get_start_sect(struct partition
*p
) {
268 return read4_little_endian(p
->start4
);
272 set_nr_sects(struct partition
*p
, unsigned int nr_sects
) {
273 store4_little_endian(p
->size4
, nr_sects
);
277 get_nr_sects(struct partition
*p
) {
278 return read4_little_endian(p
->size4
);
284 unsigned char align
[ALIGNMENT
];
285 unsigned char b
[SECTOR_SIZE
];
288 unsigned char align
[ALIGNMENT
];
289 unsigned char buffer
[0x1BE];
290 struct partition part
[4];
291 unsigned char magicflag
[2];
296 long long first_sector
; /* first sector in partition */
297 long long last_sector
; /* last sector in partition */
298 long offset
; /* offset from first sector to start of data */
299 int flags
; /* active == 0x80 */
300 int id
; /* filesystem type */
301 int num
; /* number of partition -- primary vs. logical */
303 char volume_label
[LABELSZ
+1];
305 char ostype
[OSTYPESZ
+1];
307 char fstype
[FSTYPESZ
+1];
310 char *disk_device
= DEFAULT_DEVICE
;
315 int curses_started
= 0;
317 partition_info p_info
[MAXIMUM_PARTS
];
318 partition_info ext_info
;
322 int logical_sectors
[MAXIMUM_PARTS
];
324 __sighandler_t old_SIGINT
, old_SIGTERM
;
326 int arrow_cursor
= FALSE
;
327 int display_units
= MEGABYTES
;
328 int zero_table
= FALSE
;
329 int use_partition_table_geometry
= FALSE
;
332 /* Curses screen information */
334 int warning_last_time
= FALSE
;
337 int NUM_ON_SCREEN
= 1;
340 int HEADER_START
= 0;
341 int DISK_TABLE_START
= 6;
342 int WARNING_START
= 23;
343 int COMMAND_LINE_Y
= 21;
347 int FLAGS_START
= 16;
348 int PTYPE_START
= 28;
349 int FSTYPE_START
= 38;
350 int LABEL_START
= 54;
352 int COMMAND_LINE_X
= 5;
354 static void die_x(int ret
);
355 static void draw_screen(void);
357 /* Guaranteed alloc */
359 xmalloc (size_t size
) {
367 fprintf (stderr
, _("%s: Out of memory!\n"), "cfdisk");
373 /* Some libc's have their own basename() */
375 my_basename(char *devname
) {
376 char *s
= rindex(devname
, '/');
377 return s
? s
+1 : devname
;
381 partition_type_name(unsigned char type
) {
382 struct systypes
*s
= i386_sys_types
;
384 while(s
->name
&& s
->type
!= type
)
390 partition_type_text(int i
) {
391 if (p_info
[i
].id
== UNUSABLE
)
392 return _("Unusable");
393 else if (p_info
[i
].id
== FREE_SPACE
)
394 return _("Free Space");
395 else if (p_info
[i
].id
== LINUX
) {
396 if (!strcmp(p_info
[i
].fstype
, "ext2"))
397 return _("Linux ext2");
398 else if (!strcmp(p_info
[i
].fstype
, "ext3"))
399 return _("Linux ext3");
400 else if (!strcmp(p_info
[i
].fstype
, "xfs"))
401 return _("Linux XFS");
402 else if (!strcmp(p_info
[i
].fstype
, "reiserfs"))
403 return _("Linux ReiserFS");
406 } else if (p_info
[i
].id
== OS2_OR_NTFS
) {
407 if (!strncmp(p_info
[i
].fstype
, "HPFS", 4))
408 return _("OS/2 HPFS");
409 else if (!strncmp(p_info
[i
].ostype
, "OS2", 3))
410 return _("OS/2 IFS");
411 else if (!p_info
[i
].ostype
)
412 return p_info
[i
].ostype
;
416 return partition_type_name(p_info
[i
].id
);
425 fprintf(stderr
, _("Disk has been changed.\n"));
426 fprintf(stderr
, _("Reboot the system to ensure the partition "
427 "table is correctly updated.\n"));
429 fprintf( stderr
, _("\nWARNING: If you have created or modified any\n"
430 "DOS 6.x partitions, please see the cfdisk manual\n"
431 "page for additional information.\n") );
438 get_string(char *str
, int len
, char *def
) {
456 while ((c
= getch()) != '\n' && c
!= CR
) {
467 mvaddch(y
, x
+i
, ' ');
469 } else if (use_def
) {
476 if (i
< len
&& isprint(c
)) {
497 clear_warning(void) {
500 if (!curses_started
|| !warning_last_time
)
503 move(WARNING_START
,0);
504 for (i
= 0; i
< COLS
; i
++)
507 warning_last_time
= FALSE
;
511 print_warning(char *s
) {
512 if (!curses_started
) {
513 fprintf(stderr
, "%s\n", s
);
515 mvaddstr(WARNING_START
, (COLS
-strlen(s
))/2, s
);
516 putchar(BELL
); /* CTRL-G */
518 warning_last_time
= TRUE
;
523 fatal(char *s
, int ret
) {
524 char *err1
= _("FATAL ERROR");
525 char *err2
= _("Press any key to exit cfdisk");
527 if (curses_started
) {
528 char *str
= xmalloc(strlen(s
) + strlen(err1
) + strlen(err2
) + 10);
530 sprintf(str
, "%s: %s", err1
, s
);
531 if (strlen(str
) > COLS
)
533 mvaddstr(WARNING_START
, (COLS
-strlen(str
))/2, str
);
534 sprintf(str
, "%s", err2
);
535 if (strlen(str
) > COLS
)
537 mvaddstr(WARNING_START
+1, (COLS
-strlen(str
))/2, str
);
538 putchar(BELL
); /* CTRL-G */
543 fprintf(stderr
, "%s: %s\n", err1
, s
);
555 signal(SIGINT
, old_SIGINT
);
556 signal(SIGTERM
, old_SIGTERM
);
558 SLsmg_gotorc(LINES
-1, 0);
561 mvcur(0, COLS
-1, LINES
-1, 0);
570 read_sector(char *buffer
, long long sect_num
) {
571 if (ext2_llseek(fd
, sect_num
*SECTOR_SIZE
, SEEK_SET
) < 0)
572 fatal(_("Cannot seek on disk drive"), 2);
573 if (read(fd
, buffer
, SECTOR_SIZE
) != SECTOR_SIZE
)
574 fatal(_("Cannot read disk drive"), 2);
578 write_sector(char *buffer
, long long sect_num
) {
579 if (ext2_llseek(fd
, sect_num
*SECTOR_SIZE
, SEEK_SET
) < 0)
580 fatal(_("Cannot seek on disk drive"), 2);
581 if (write(fd
, buffer
, SECTOR_SIZE
) != SECTOR_SIZE
)
582 fatal(_("Cannot write disk drive"), 2);
586 dos_copy_to_info(char *to
, int tosz
, char *from
, int fromsz
) {
589 for(i
=0; i
<tosz
&& i
<fromsz
&& isascii(from
[i
]); i
++)
595 get_dos_label(int i
) {
597 #define DOS_OSTYPE_OFFSET 3
598 #define DOS_LABEL_OFFSET 43
599 #define DOS_FSTYPE_OFFSET 54
600 #define DOS_OSTYPE_SZ 8
601 #define DOS_LABEL_SZ 11
602 #define DOS_FSTYPE_SZ 8
605 offset
= (p_info
[i
].first_sector
+ p_info
[i
].offset
) * SECTOR_SIZE
;
606 if (ext2_llseek(fd
, offset
, SEEK_SET
) == offset
607 && read(fd
, §or
, sizeof(sector
)) == sizeof(sector
)) {
608 dos_copy_to_info(p_info
[i
].ostype
, OSTYPESZ
,
609 sector
+DOS_OSTYPE_OFFSET
, DOS_OSTYPE_SZ
);
610 dos_copy_to_info(p_info
[i
].volume_label
, LABELSZ
,
611 sector
+DOS_LABEL_OFFSET
, DOS_LABEL_SZ
);
612 dos_copy_to_info(p_info
[i
].fstype
, FSTYPESZ
,
613 sector
+DOS_FSTYPE_OFFSET
, DOS_FSTYPE_SZ
);
617 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
618 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
619 struct reiserfs_super_block
{
626 is_reiserfs_magic_string(const struct reiserfs_super_block
*rs
) {
627 return (!strncmp(rs
->s_magic
, REISERFS_SUPER_MAGIC_STRING
,
628 strlen(REISERFS_SUPER_MAGIC_STRING
)) ||
629 !strncmp(rs
->s_magic
, REISER2FS_SUPER_MAGIC_STRING
,
630 strlen(REISER2FS_SUPER_MAGIC_STRING
)));
634 get_linux_label(int i
) {
636 #define EXT2LABELSZ 16
637 #define EXT2_SUPER_MAGIC 0xEF53
638 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
639 struct ext2_super_block
{
641 unsigned char s_magic
[2];
643 unsigned char s_feature_compat
[4];
645 char s_volume_name
[EXT2LABELSZ
];
646 char s_last_mounted
[64];
650 #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
651 struct reiserfs_super_block reiserfsb
;
653 #define XFS_SUPER_MAGIC "XFSB"
654 #define XFSLABELSZ 12
655 struct xfs_super_block
{
656 unsigned char s_magic
[4];
657 unsigned char s_dummy0
[104];
658 unsigned char s_fname
[XFSLABELSZ
];
659 unsigned char s_dummy1
[904];
666 offset
= (p_info
[i
].first_sector
+ p_info
[i
].offset
) * SECTOR_SIZE
668 if (ext2_llseek(fd
, offset
, SEEK_SET
) == offset
669 && read(fd
, &e2fsb
, sizeof(e2fsb
)) == sizeof(e2fsb
)
670 && e2fsb
.s_magic
[0] + (e2fsb
.s_magic
[1]<<8) == EXT2_SUPER_MAGIC
) {
671 label
= e2fsb
.s_volume_name
;
672 for(j
=0; j
<EXT2LABELSZ
&& j
<LABELSZ
&& isprint(label
[j
]); j
++)
673 p_info
[i
].volume_label
[j
] = label
[j
];
674 p_info
[i
].volume_label
[j
] = 0;
676 if (e2fsb
.s_feature_compat
[0]&EXT3_FEATURE_COMPAT_HAS_JOURNAL
)
677 strncpy(p_info
[i
].fstype
, "ext3", FSTYPESZ
);
679 strncpy(p_info
[i
].fstype
, "ext2", FSTYPESZ
);
683 offset
= (p_info
[i
].first_sector
+ p_info
[i
].offset
) * SECTOR_SIZE
+ 0;
684 if (ext2_llseek(fd
, offset
, SEEK_SET
) == offset
685 && read(fd
, &xfsb
, sizeof(xfsb
)) == sizeof(xfsb
)
686 && !strcmp(xfsb
.s_magic
, XFS_SUPER_MAGIC
)) {
687 label
= xfsb
.s_fname
;
688 for(j
=0; j
<XFSLABELSZ
&& j
<LABELSZ
&& isprint(label
[j
]); j
++)
689 p_info
[i
].volume_label
[j
] = label
[j
];
690 p_info
[i
].volume_label
[j
] = 0;
691 strncpy(p_info
[i
].fstype
, "xfs", FSTYPESZ
);
696 offset
= (p_info
[i
].first_sector
+ p_info
[i
].offset
) * SECTOR_SIZE
697 + REISERFS_DISK_OFFSET_IN_BYTES
;
698 if (ext2_llseek(fd
, offset
, SEEK_SET
) == offset
699 && read(fd
, &reiserfsb
, 1024) == 1024
700 && is_reiserfs_magic_string(&reiserfsb
)) {
701 strncpy(p_info
[i
].fstype
, "reiserfs", FSTYPESZ
);
707 check_part_info(void) {
708 int i
, pri
= 0, log
= 0;
710 for (i
= 0; i
< num_parts
; i
++)
711 if (p_info
[i
].id
> 0 && IS_PRIMARY(p_info
[i
].num
))
713 else if (p_info
[i
].id
> 0 && IS_LOGICAL(p_info
[i
].num
))
715 if (is_extended(ext_info
.id
)) {
719 ext_info
.first_sector
= 0;
720 ext_info
.last_sector
= 0;
723 ext_info
.id
= FREE_SPACE
;
724 ext_info
.num
= PRIMARY
;
729 for (i
= 0; i
< num_parts
; i
++)
730 if (p_info
[i
].id
== FREE_SPACE
|| p_info
[i
].id
== UNUSABLE
) {
731 if (is_extended(ext_info
.id
)) {
732 if (p_info
[i
].first_sector
>= ext_info
.first_sector
&&
733 p_info
[i
].last_sector
<= ext_info
.last_sector
) {
734 p_info
[i
].id
= FREE_SPACE
;
735 p_info
[i
].num
= LOGICAL
;
737 p_info
[i
-1].first_sector
>=
738 ext_info
.first_sector
&&
739 p_info
[i
-1].last_sector
<=
740 ext_info
.last_sector
) {
741 p_info
[i
].id
= FREE_SPACE
;
742 p_info
[i
].num
= LOGICAL
;
743 } else if (i
< num_parts
-1 &&
744 p_info
[i
+1].first_sector
>=
745 ext_info
.first_sector
&&
746 p_info
[i
+1].last_sector
<=
747 ext_info
.last_sector
) {
748 p_info
[i
].id
= FREE_SPACE
;
749 p_info
[i
].num
= LOGICAL
;
751 p_info
[i
].id
= UNUSABLE
;
752 } else /* if (!is_extended(ext_info.id)) */
753 p_info
[i
].id
= UNUSABLE
;
754 } else /* if (p_info[i].id > 0) */
755 while (0); /* Leave these alone */
756 } else { /* if (pri < 4) */
757 for (i
= 0; i
< num_parts
; i
++) {
758 if (p_info
[i
].id
== UNUSABLE
)
759 p_info
[i
].id
= FREE_SPACE
;
760 if (p_info
[i
].id
== FREE_SPACE
) {
761 if (is_extended(ext_info
.id
)) {
762 if (p_info
[i
].first_sector
>= ext_info
.first_sector
&&
763 p_info
[i
].last_sector
<= ext_info
.last_sector
)
764 p_info
[i
].num
= LOGICAL
;
766 p_info
[i
-1].first_sector
>=
767 ext_info
.first_sector
&&
768 p_info
[i
-1].last_sector
<=
769 ext_info
.last_sector
)
770 p_info
[i
].num
= PRI_OR_LOG
;
771 else if (i
< num_parts
-1 &&
772 p_info
[i
+1].first_sector
>=
773 ext_info
.first_sector
&&
774 p_info
[i
+1].last_sector
<=
775 ext_info
.last_sector
)
776 p_info
[i
].num
= PRI_OR_LOG
;
778 p_info
[i
].num
= PRIMARY
;
779 } else /* if (!is_extended(ext_info.id)) */
780 p_info
[i
].num
= PRI_OR_LOG
;
781 } else /* if (p_info[i].id > 0) */
782 while (0); /* Leave these alone */
791 for (p
= i
; p
< num_parts
; p
++)
792 p_info
[p
] = p_info
[p
+1];
795 if (cur_part
== num_parts
)
800 insert_empty_part(int i
, long long first
, long long last
) {
803 for (p
= num_parts
; p
> i
; p
--)
804 p_info
[p
] = p_info
[p
-1];
806 p_info
[i
].first_sector
= first
;
807 p_info
[i
].last_sector
= last
;
808 p_info
[i
].offset
= 0;
810 p_info
[i
].id
= FREE_SPACE
;
811 p_info
[i
].num
= PRI_OR_LOG
;
812 p_info
[i
].volume_label
[0] = 0;
813 p_info
[i
].fstype
[0] = 0;
814 p_info
[i
].ostype
[0] = 0;
821 int num
= p_info
[i
].num
;
823 if (i
> 0 && (p_info
[i
-1].id
== FREE_SPACE
||
824 p_info
[i
-1].id
== UNUSABLE
)) {
825 /* Merge with previous partition */
826 p_info
[i
-1].last_sector
= p_info
[i
].last_sector
;
830 if (i
< num_parts
- 1 && (p_info
[i
+1].id
== FREE_SPACE
||
831 p_info
[i
+1].id
== UNUSABLE
)) {
832 /* Merge with next partition */
833 p_info
[i
+1].first_sector
= p_info
[i
].first_sector
;
838 p_info
[i
].first_sector
= p_info
[i
-1].last_sector
+ 1;
840 p_info
[i
].first_sector
= 0;
842 if (i
< num_parts
- 1)
843 p_info
[i
].last_sector
= p_info
[i
+1].first_sector
- 1;
845 p_info
[i
].last_sector
= total_size
- 1;
847 p_info
[i
].offset
= 0;
849 p_info
[i
].id
= FREE_SPACE
;
850 p_info
[i
].num
= PRI_OR_LOG
;
852 if (IS_LOGICAL(num
)) {
853 /* We have a logical partition --> shrink the extended partition
854 * if (1) this is the first logical drive, or (2) this is the
855 * last logical drive; and if there are any other logical drives
856 * then renumber the ones after "num".
858 if (i
== 0 || (i
> 0 && IS_PRIMARY(p_info
[i
-1].num
))) {
859 ext_info
.first_sector
= p_info
[i
].last_sector
+ 1;
862 if (i
== num_parts
-1 ||
863 (i
< num_parts
-1 && IS_PRIMARY(p_info
[i
+1].num
)))
864 ext_info
.last_sector
= p_info
[i
].first_sector
- 1;
865 for (i
= 0; i
< num_parts
; i
++)
866 if (p_info
[i
].num
> num
)
870 /* Clean up the rest of the partitions */
875 add_part(int num
, int id
, int flags
, long long first
, long long last
,
876 long long offset
, int want_label
, char **errmsg
) {
877 int i
, pri
= 0, log
= 0;
879 if (num_parts
== MAXIMUM_PARTS
) {
880 *errmsg
= _("Too many partitions");
885 *errmsg
= _("Partition begins before sector 0");
890 *errmsg
= _("Partition ends before sector 0");
894 if (first
>= total_size
) {
895 *errmsg
= _("Partition begins after end-of-disk");
899 if (last
>= actual_size
) {
900 *errmsg
= _("Partition ends after end-of-disk");
904 if (last
>= total_size
) {
905 *errmsg
= _("Partition ends in the final partial cylinder");
909 for (i
= 0; i
< num_parts
; i
++) {
910 if (p_info
[i
].id
> 0 && IS_PRIMARY(p_info
[i
].num
))
912 else if (p_info
[i
].id
> 0 && IS_LOGICAL(p_info
[i
].num
))
915 if (is_extended(ext_info
.id
) && log
> 0)
918 if (IS_PRIMARY(num
)) {
920 return -1; /* no room for more */
925 for (i
= 0; i
< num_parts
&& p_info
[i
].last_sector
< first
; i
++);
927 if (i
< num_parts
&& p_info
[i
].id
!= FREE_SPACE
) {
928 if (last
< p_info
[i
].first_sector
)
929 *errmsg
= _("logical partitions not in disk order");
930 else if (first
+ offset
<= p_info
[i
].last_sector
&&
931 p_info
[i
].first_sector
+ p_info
[i
].offset
<= last
)
932 *errmsg
= _("logical partitions overlap");
934 *errmsg
= _("enlarged logical partitions overlap");
938 if (i
== num_parts
|| last
> p_info
[i
].last_sector
) {
942 if (is_extended(id
)) {
943 if (ext_info
.id
!= FREE_SPACE
) {
944 return -1; /* second extended */
946 else if (IS_PRIMARY(num
)) {
947 ext_info
.first_sector
= first
;
948 ext_info
.last_sector
= last
;
949 ext_info
.offset
= offset
;
950 ext_info
.flags
= flags
;
953 ext_info
.volume_label
[0] = 0;
954 ext_info
.fstype
[0] = 0;
955 ext_info
.ostype
[0] = 0;
958 return -1; /* explicit extended logical */
962 if (IS_LOGICAL(num
)) {
963 if (!is_extended(ext_info
.id
)) {
964 print_warning(_("!!!! Internal error creating logical "
965 "drive with no extended partition !!!!"));
967 /* We might have a logical partition outside of the extended
968 * partition's range --> we have to extend the extended
969 * partition's range to encompass this new partition, but we
970 * must make sure that there are no primary partitions between
971 * it and the closest logical drive in extended partition.
973 if (first
< ext_info
.first_sector
) {
974 if (i
< num_parts
-1 && IS_PRIMARY(p_info
[i
+1].num
)) {
975 print_warning(_("Cannot create logical drive here -- would create two extended partitions"));
979 ext_info
.first_sector
= 0;
980 ext_info
.offset
= first
= offset
;
982 ext_info
.first_sector
= first
;
985 } else if (last
> ext_info
.last_sector
) {
986 if (i
> 0 && IS_PRIMARY(p_info
[i
-1].num
)) {
987 print_warning(_("Cannot create logical drive here -- would create two extended partitions"));
990 ext_info
.last_sector
= last
;
996 if (first
!= p_info
[i
].first_sector
&&
997 !(IS_LOGICAL(num
) && first
== offset
)) {
998 insert_empty_part(i
, p_info
[i
].first_sector
, first
-1);
1002 if (last
!= p_info
[i
].last_sector
)
1003 insert_empty_part(i
+1, last
+1, p_info
[i
].last_sector
);
1005 p_info
[i
].first_sector
= first
;
1006 p_info
[i
].last_sector
= last
;
1007 p_info
[i
].offset
= offset
;
1008 p_info
[i
].flags
= flags
;
1010 p_info
[i
].num
= num
;
1011 p_info
[i
].volume_label
[0] = 0;
1012 p_info
[i
].fstype
[0] = 0;
1013 p_info
[i
].ostype
[0] = 0;
1015 if (may_have_dos_label(id
))
1017 else if (id
== LINUX
)
1027 find_primary(void) {
1028 int num
= 0, cur
= 0;
1030 while (cur
< num_parts
&& IS_PRIMARY(num
))
1031 if ((p_info
[cur
].id
> 0 && p_info
[cur
].num
== num
) ||
1032 (is_extended(ext_info
.id
) && ext_info
.num
== num
)) {
1038 if (!IS_PRIMARY(num
))
1045 find_logical(int i
) {
1049 for (j
= i
; j
< num_parts
&& num
== -1; j
++)
1050 if (p_info
[j
].id
> 0 && IS_LOGICAL(p_info
[j
].num
))
1051 num
= p_info
[j
].num
;
1055 for (j
= 0; j
< num_parts
; j
++)
1056 if (p_info
[j
].id
> 0 && p_info
[j
].num
== num
)
1064 inc_logical(int i
) {
1067 for (j
= i
; j
< num_parts
; j
++)
1068 if (p_info
[j
].id
> 0 && IS_LOGICAL(p_info
[j
].num
))
1072 /* Command menu support by Janne Kukonlehto <jtklehto@phoenix.oulu.fi> September 1994 */
1074 /* Constants for menuType parameter of menuSelect function */
1075 #define MENU_HORIZ 1
1077 #define MENU_ACCEPT_OTHERS 4
1078 #define MENU_BUTTON 8
1079 /* Miscellenous constants */
1080 #define MENU_SPACING 2
1081 #define MENU_MAX_ITEMS 256 /* for simpleMenu function */
1084 #define MENU_RIGHT 3
1089 int key
; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */
1090 char *name
; /* Item name, should be eight characters with current implementation */
1091 char *desc
; /* Item description to be printed when item is selected */
1095 * Actual function which prints the button bar and highlights the active button
1096 * Should not be called directly. Call function menuSelect instead.
1100 menuUpdate( int y
, int x
, struct MenuItem
*menuItems
, int itemLength
,
1101 char *available
, int menuType
, int current
) {
1102 int i
, lmargin
= x
, ymargin
= y
;
1105 /* Print available buttons */
1106 move( y
, x
); clrtoeol();
1108 for( i
= 0; menuItems
[i
].key
; i
++ ) {
1113 /* Search next available button */
1114 while( menuItems
[i
].key
&& !strchr(available
, menuItems
[i
].key
) )
1117 if( !menuItems
[i
].key
) break; /* No more menu items */
1119 /* If selected item is not available and we have bypassed it,
1120 make current item selected */
1121 if( current
< i
&& menuItems
[current
].key
< 0 ) current
= i
;
1123 /* If current item is selected, highlight it */
1124 if( current
== i
) /*attron( A_REVERSE )*/ standout ();
1127 /* Because of a bug in gettext() we must not translate empty strings */
1128 if (menuItems
[i
].name
[0])
1129 mi
= _(menuItems
[i
].name
);
1132 lenName
= strlen( mi
);
1134 if(lenName
> itemLength
|| lenName
>= sizeof(buff
))
1135 print_warning(_("Menu item too long. Menu may look odd."));
1137 if (lenName
>= sizeof(buff
)) { /* truncate ridiculously long string */
1138 xstrncpy(buff
, mi
, sizeof(buff
));
1139 } else if (lenName
>= itemLength
) {
1140 snprintf(buff
, sizeof(buff
),
1141 (menuType
& MENU_BUTTON
) ? "[%s]" : "%s", mi
);
1143 snprintf(buff
, sizeof(buff
),
1144 (menuType
& MENU_BUTTON
) ? "[%*s%-*s]" : "%*s%-*s",
1145 (itemLength
- lenName
) / 2, "",
1146 (itemLength
- lenName
+ 1) / 2 + lenName
, mi
);
1148 mvaddstr( y
, x
, buff
);
1150 /* Lowlight after selected item */
1151 if( current
== i
) /*attroff( A_REVERSE )*/ standend ();
1153 /* Calculate position for the next item */
1154 if( menuType
& MENU_VERT
)
1157 if( y
>= WARNING_START
)
1160 x
+= itemLength
+ MENU_SPACING
;
1161 if( menuType
& MENU_BUTTON
) x
+= 2;
1166 x
+= itemLength
+ MENU_SPACING
;
1167 if( menuType
& MENU_BUTTON
) x
+= 2;
1168 if( x
> COLUMNS
- lmargin
- 12 )
1176 /* Print the description of selected item */
1177 mcd
= _(menuItems
[current
].desc
);
1178 mvaddstr( WARNING_START
+ 1, (COLUMNS
- strlen( mcd
)) / 2, mcd
);
1182 /* This function takes a list of menu items, lets the user choose one *
1183 * and returns the keyboard shortcut value of the selected menu item */
1186 menuSelect( int y
, int x
, struct MenuItem
*menuItems
, int itemLength
,
1187 char *available
, int menuType
, int menuDefault
) {
1188 int i
, ylast
= y
, key
= 0, current
= menuDefault
;
1190 if( !( menuType
& ( MENU_HORIZ
| MENU_VERT
) ) ) {
1191 print_warning(_("Menu without direction. Defaulting horizontal."));
1192 menuType
|= MENU_HORIZ
;
1195 /* Make sure that the current is one of the available items */
1196 while( !strchr(available
, menuItems
[current
].key
) ) {
1198 if( !menuItems
[current
].key
) current
= 0;
1201 /* Repeat until allowable choice has been made */
1203 /* Display the menu and read a command */
1204 ylast
= menuUpdate( y
, x
, menuItems
, itemLength
, available
,
1205 menuType
, current
);
1209 /* Clear out all prompts and such */
1211 for (i
= y
; i
< ylast
; i
++) {
1215 move( WARNING_START
+ 1, 0 );
1218 /* Cursor keys - possibly split by slow connection */
1220 /* Check whether this is a real ESC or one of extended keys */
1221 /*nodelay(stdscr, TRUE);*/
1223 /*nodelay(stdscr, FALSE);*/
1225 if( key
== /*ERR*/ ESC
) {
1226 /* This is a real ESC */
1229 if(key
== '[' || key
== 'O') {
1230 /* This is one extended keys */
1234 case 'A': /* Up arrow */
1237 case 'B': /* Down arrow */
1240 case 'C': /* Right arrow */
1243 case 'D': /* Left arrow */
1252 /* Enter equals the keyboard shortcut of current menu item */
1254 key
= menuItems
[current
].key
;
1256 /* Give alternatives for arrow keys in case the window manager
1260 if (key
== UPKEY
) /* ^P */
1262 if (key
== DOWNKEY
) /* ^N */
1265 if (key
== MENU_UP
) {
1266 if( menuType
& MENU_VERT
) {
1270 while( menuItems
[current
+1].key
)
1272 } while( !strchr( available
, menuItems
[current
].key
));
1277 if (key
== MENU_DOWN
) {
1278 if( menuType
& MENU_VERT
) {
1281 if( !menuItems
[current
].key
) current
= 0 ;
1282 } while( !strchr( available
, menuItems
[current
].key
));
1287 if (key
== MENU_RIGHT
) {
1288 if( menuType
& MENU_HORIZ
) {
1291 if( !menuItems
[current
].key
)
1293 } while( !strchr( available
, menuItems
[current
].key
));
1298 if (key
== MENU_LEFT
) {
1299 if( menuType
& MENU_HORIZ
) {
1303 while( menuItems
[current
+ 1].key
)
1306 } while( !strchr( available
, menuItems
[current
].key
));
1311 /* Should all keys to be accepted? */
1312 if( key
&& (menuType
& MENU_ACCEPT_OTHERS
) ) break;
1314 /* Is pressed key among acceptable ones? */
1315 if( key
&& (strchr(available
, tolower(key
)) || strchr(available
, key
)))
1318 /* The key has not been accepted so far -> let's reject it */
1322 print_warning(_("Illegal key"));
1326 /* Clear out prompts and such */
1328 for( i
= y
; i
<= ylast
; i
++ ) {
1332 move( WARNING_START
+ 1, 0 );
1337 /* A function which displays "Press a key to continue" *
1338 * and waits for a keypress. *
1339 * Perhaps calling function menuSelect is a bit overkill but who cares? */
1342 menuContinue(void) {
1343 static struct MenuItem menuContinueBtn
[]=
1345 { 'c', "", N_("Press a key to continue") },
1349 menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1350 menuContinueBtn
, 0, "c", MENU_HORIZ
| MENU_ACCEPT_OTHERS
, 0 );
1353 /* Function menuSelect takes way too many parameters *
1354 * Luckily, most of time we can do with this function */
1357 menuSimple(struct MenuItem
*menuItems
, int menuDefault
) {
1358 int i
, j
, itemLength
= 0;
1359 char available
[MENU_MAX_ITEMS
];
1361 for(i
= 0; menuItems
[i
].key
; i
++)
1363 j
= strlen( _(menuItems
[i
].name
) );
1364 if( j
> itemLength
) itemLength
= j
;
1365 available
[i
] = menuItems
[i
].key
;
1368 return menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuItems
, itemLength
,
1369 available
, MENU_HORIZ
| MENU_BUTTON
, menuDefault
);
1372 /* End of command menu support code */
1376 char response
[LINE_LENGTH
], def
[LINE_LENGTH
];
1378 long long first
= p_info
[i
].first_sector
;
1379 long long last
= p_info
[i
].last_sector
;
1380 long long offset
= 0;
1384 long long num_sects
= last
- first
+ 1;
1387 double sectors_per_MB
= K
*K
/ 512.0;
1389 if (p_info
[i
].num
== PRI_OR_LOG
) {
1390 static struct MenuItem menuPartType
[]=
1392 { 'p', N_("Primary"), N_("Create a new primary partition") },
1393 { 'l', N_("Logical"), N_("Create a new logical partition") },
1394 { ESC
, N_("Cancel"), N_("Don't create a partition") },
1398 c
= menuSimple( menuPartType
, 0 );
1399 if (toupper(c
) == 'P')
1400 num
= find_primary();
1401 else if (toupper(c
) == 'L')
1402 num
= find_logical(i
);
1405 } else if (p_info
[i
].num
== PRIMARY
)
1406 num
= find_primary();
1407 else if (p_info
[i
].num
== LOGICAL
)
1408 num
= find_logical(i
);
1410 print_warning(_("!!! Internal error !!!"));
1412 snprintf(def
, sizeof(def
), "%.2f", num_sects
/sectors_per_MB
);
1413 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
, _("Size (in MB): "));
1414 if ((len
= get_string(response
, LINE_LENGTH
, def
)) <= 0 &&
1418 #define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/cylinder_size))
1420 j
< len
-1 && (isdigit(response
[j
]) || response
[j
] == '.');
1422 if (toupper(response
[j
]) == 'K') {
1423 num_sects
= num_cyls(atof(response
)*K
)*cylinder_size
;
1424 } else if (toupper(response
[j
]) == 'M') {
1425 num_sects
= num_cyls(atof(response
)*K
*K
)*cylinder_size
;
1426 } else if (toupper(response
[j
]) == 'G') {
1427 num_sects
= num_cyls(atof(response
)*K
*K
*K
)*cylinder_size
;
1428 } else if (toupper(response
[j
]) == 'C') {
1429 num_sects
= round_int(atof(response
))*cylinder_size
;
1430 } else if (toupper(response
[j
]) == 'S') {
1431 num_sects
= round_int(atof(response
));
1433 num_sects
= num_cyls(atof(response
)*K
*K
)*cylinder_size
;
1437 if (num_sects
<= 0 ||
1438 num_sects
> p_info
[i
].last_sector
- p_info
[i
].first_sector
+ 1)
1441 move( COMMAND_LINE_Y
, COMMAND_LINE_X
); clrtoeol();
1442 if (num_sects
< p_info
[i
].last_sector
- p_info
[i
].first_sector
+ 1) {
1443 /* Determine where inside free space to put partition.
1445 static struct MenuItem menuPlace
[]=
1447 { 'b', N_("Beginning"), N_("Add partition at beginning of free space") },
1448 { 'e', N_("End"), N_("Add partition at end of free space") },
1449 { ESC
, N_("Cancel"), N_("Don't create a partition") },
1452 c
= menuSimple( menuPlace
, 0 );
1453 if (toupper(c
) == 'B')
1454 last
= first
+ num_sects
- 1;
1455 else if (toupper(c
) == 'E')
1456 first
= last
- num_sects
+ 1;
1461 if (IS_LOGICAL(num
) && !is_extended(ext_info
.id
)) {
1462 /* We want to add a logical partition, but need to create an
1463 * extended partition first.
1465 if ((ext
= find_primary()) < 0) {
1466 print_warning(_("No room to create the extended partition"));
1469 (void) add_part(ext
, DOS_EXTENDED
, 0, first
, last
,
1470 (first
== 0 ? sectors
: 0), 0, &errmsg
);
1471 first
= ext_info
.first_sector
+ ext_info
.offset
;
1474 if (IS_LOGICAL(num
))
1477 /* Now we have a complete partition to ourselves */
1478 if (first
== 0 || IS_LOGICAL(num
))
1481 (void) add_part(num
, id
, flags
, first
, last
, offset
, 0, &errmsg
);
1485 get_kernel_geometry(void) {
1487 struct hd_geometry geometry
;
1489 if (!ioctl(fd
, HDIO_GETGEO
, &geometry
)) {
1490 kern_heads
= geometry
.heads
;
1491 kern_sectors
= geometry
.sectors
;
1497 said_yes(char answer
) {
1504 yn
= rpmatch(reply
); /* 1: yes, 0: no, -1: ? */
1508 return (answer
== 'y' || answer
== 'Y');
1512 get_partition_table_geometry(partition_table
*bufp
) {
1513 struct partition
*p
;
1518 if (bufp
->p
.magicflag
[0] != PART_TABLE_FLAG0
||
1519 bufp
->p
.magicflag
[1] != PART_TABLE_FLAG1
) {
1520 /* Matthew Wilcox: slightly friendlier version of
1521 fatal(_("Bad signature on partition table"), 3);
1524 mvaddstr(WARNING_START
, 0,
1525 _("No partition table or unknown signature on partition table"));
1526 mvaddstr(WARNING_START
+1, 0,
1527 _("Do you wish to start with a zero table [y/N] ?"));
1531 if (cont
== EOF
|| !said_yes(cont
))
1536 /* Oskar Liljeblad suggested:
1537 Bad signature blah blah
1538 If this is a brand new harddrive that has not been partitioned
1539 before, please run cfdisk -z.
1544 for (i
=0; i
<4; i
++) {
1545 p
= &(bufp
->p
.part
[i
]);
1546 if (p
->sys_ind
!= 0) {
1547 h
= p
->end_head
+ 1;
1548 s
= (p
->end_sector
& 077);
1553 } else if (hh
!= h
|| ss
!= s
)
1558 if (!first
&& !bad
) {
1565 decide_on_geometry(void) {
1566 heads
= (user_heads
? user_heads
:
1567 pt_heads
? pt_heads
:
1568 kern_heads
? kern_heads
: 255);
1569 sectors
= (user_sectors
? user_sectors
:
1570 pt_sectors
? pt_sectors
:
1571 kern_sectors
? kern_sectors
: 63);
1572 cylinder_size
= heads
*sectors
;
1573 cylinders
= actual_size
/cylinder_size
;
1574 if (user_cylinders
> 0)
1575 cylinders
= user_cylinders
;
1577 total_size
= cylinder_size
*cylinders
;
1578 if (total_size
> actual_size
)
1579 print_warning(_("You specified more cylinders than fit on disk"));
1583 clear_p_info(void) {
1585 p_info
[0].first_sector
= 0;
1586 p_info
[0].last_sector
= total_size
- 1;
1587 p_info
[0].offset
= 0;
1588 p_info
[0].flags
= 0;
1589 p_info
[0].id
= FREE_SPACE
;
1590 p_info
[0].num
= PRI_OR_LOG
;
1592 ext_info
.first_sector
= 0;
1593 ext_info
.last_sector
= 0;
1594 ext_info
.offset
= 0;
1596 ext_info
.id
= FREE_SPACE
;
1597 ext_info
.num
= PRIMARY
;
1604 unsigned long long bytes
;
1605 struct partition
*p
;
1606 partition_table buffer
;
1607 partition_info tmp_ext
= { 0, 0, 0, 0, FREE_SPACE
, PRIMARY
};
1609 if ((fd
= open(disk_device
, O_RDWR
)) < 0) {
1610 if ((fd
= open(disk_device
, O_RDONLY
)) < 0)
1611 fatal(_("Cannot open disk drive"), 2);
1612 opentype
= O_RDONLY
;
1613 print_warning(_("Opened disk read-only - you have no permission to write"));
1614 if (curses_started
) {
1623 /* Blocks are visible in more than one way:
1624 e.g. as block on /dev/hda and as block on /dev/hda3
1625 By a bug in the Linux buffer cache, we will see the old
1626 contents of /dev/hda when the change was made to /dev/hda3.
1627 In order to avoid this, discard all blocks on /dev/hda.
1628 Note that partition table blocks do not live in /dev/hdaN,
1629 so this only plays a role if we want to show volume labels. */
1630 ioctl(fd
, BLKFLSBUF
); /* ignore errors */
1631 /* e.g. Permission Denied */
1633 if (ioctl(fd
, BLKGETSIZE64
, &bytes
) == 0)
1634 actual_size
= (bytes
>> 9);
1636 unsigned long sz
= 0;
1638 if (ioctl(fd
, BLKGETSIZE
, &sz
))
1639 fatal(_("Cannot get disk size"), 3);
1643 read_sector(buffer
.c
.b
, 0);
1645 get_kernel_geometry();
1647 if (!zero_table
|| use_partition_table_geometry
)
1648 get_partition_table_geometry(& buffer
);
1650 decide_on_geometry();
1657 for (i
= 0; i
< 4; i
++) {
1658 p
= & buffer
.p
.part
[i
];
1659 bs
= get_start_sect(p
);
1660 bsz
= get_nr_sects(p
);
1662 if (p
->sys_ind
> 0 &&
1663 add_part(i
, p
->sys_ind
, p
->boot_ind
,
1664 ((bs
<= sectors
) ? 0 : bs
), bs
+ bsz
- 1,
1665 ((bs
<= sectors
) ? bs
: 0), 1, &errmsg
)) {
1666 char *bad
= _("Bad primary partition");
1667 char *msg
= (char *) xmalloc(strlen(bad
) + strlen(errmsg
) + 30);
1668 sprintf(msg
, "%s %d: %s", bad
, i
, errmsg
);
1671 if (is_extended(buffer
.p
.part
[i
].sys_ind
))
1675 if (is_extended(tmp_ext
.id
)) {
1677 logical_sectors
[logical
] =
1678 ext_info
.first_sector
+ ext_info
.offset
;
1679 read_sector(buffer
.c
.b
, logical_sectors
[logical
++]);
1683 pn
< 4 && (!buffer
.p
.part
[pn
].sys_ind
||
1684 is_extended(buffer
.p
.part
[pn
].sys_ind
));
1688 p
= & buffer
.p
.part
[pn
];
1689 bs
= get_start_sect(p
);
1690 bsz
= get_nr_sects(p
);
1692 if (add_part(i
++, p
->sys_ind
, p
->boot_ind
,
1693 logical_sectors
[logical
-1],
1694 logical_sectors
[logical
-1] + bs
+ bsz
- 1,
1696 char *bad
= _("Bad logical partition");
1697 char *msg
= (char *) xmalloc(strlen(bad
) + strlen(errmsg
) + 30);
1698 sprintf(msg
, "%s %d: %s", bad
, i
, errmsg
);
1704 pn
< 4 && !is_extended(buffer
.p
.part
[pn
].sys_ind
);
1707 p
= & buffer
.p
.part
[pn
];
1708 bs
= get_start_sect(p
);
1709 logical_sectors
[logical
] = ext_info
.first_sector
1710 + ext_info
.offset
+ bs
;
1711 read_sector(buffer
.c
.b
, logical_sectors
[logical
++]);
1713 } while (pn
< 4 && logical
< MAXIMUM_PARTS
-4);
1719 fill_part_table(struct partition
*p
, partition_info
*pi
) {
1722 p
->boot_ind
= pi
->flags
;
1723 p
->sys_ind
= pi
->id
;
1724 begin
= pi
->first_sector
+ pi
->offset
;
1725 if (IS_LOGICAL(pi
->num
))
1726 set_start_sect(p
,pi
->offset
);
1728 set_start_sect(p
,begin
);
1729 set_nr_sects(p
, pi
->last_sector
- begin
+ 1);
1730 set_hsc_begin(p
, begin
);
1731 set_hsc_end(p
, pi
->last_sector
);
1735 fill_primary_table(partition_table
*buffer
) {
1738 /* Zero out existing table */
1739 for (i
= 0x1BE; i
< SECTOR_SIZE
; i
++)
1742 for (i
= 0; i
< num_parts
; i
++)
1743 if (IS_PRIMARY(p_info
[i
].num
))
1744 fill_part_table(&(buffer
->p
.part
[p_info
[i
].num
]), &(p_info
[i
]));
1746 if (is_extended(ext_info
.id
))
1747 fill_part_table(&(buffer
->p
.part
[ext_info
.num
]), &ext_info
);
1749 buffer
->p
.magicflag
[0] = PART_TABLE_FLAG0
;
1750 buffer
->p
.magicflag
[1] = PART_TABLE_FLAG1
;
1754 fill_logical_table(partition_table
*buffer
, partition_info
*pi
) {
1755 struct partition
*p
;
1758 for (i
= 0; i
< logical
&& pi
->first_sector
!= logical_sectors
[i
]; i
++);
1759 if (i
== logical
|| buffer
->p
.magicflag
[0] != PART_TABLE_FLAG0
1760 || buffer
->p
.magicflag
[1] != PART_TABLE_FLAG1
)
1761 for (i
= 0; i
< SECTOR_SIZE
; i
++)
1764 /* Zero out existing table */
1765 for (i
= 0x1BE; i
< SECTOR_SIZE
; i
++)
1768 fill_part_table(&(buffer
->p
.part
[0]), pi
);
1771 i
< num_parts
&& pi
->num
!= p_info
[i
].num
- 1;
1774 if (i
< num_parts
) {
1775 p
= &(buffer
->p
.part
[1]);
1779 p
->sys_ind
= DOS_EXTENDED
;
1780 set_start_sect(p
, pi
->first_sector
- ext_info
.first_sector
- ext_info
.offset
);
1781 set_nr_sects(p
, pi
->last_sector
- pi
->first_sector
+ 1);
1782 set_hsc_begin(p
, pi
->first_sector
);
1783 set_hsc_end(p
, pi
->last_sector
);
1786 buffer
->p
.magicflag
[0] = PART_TABLE_FLAG0
;
1787 buffer
->p
.magicflag
[1] = PART_TABLE_FLAG1
;
1791 write_part_table(void) {
1792 int i
, ct
, done
= FALSE
, len
;
1793 partition_table buffer
;
1796 char response
[LINE_LENGTH
];
1798 if (opentype
== O_RDONLY
) {
1799 print_warning(_("Opened disk read-only - you have no permission to write"));
1807 if(fstat(fd
, &s
) == 0 && S_ISBLK(s
.st_mode
))
1811 print_warning(_("Warning!! This may destroy data on your disk!"));
1814 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1815 _("Are you sure you want write the partition table "
1816 "to disk? (yes or no): "));
1817 len
= get_string(response
, LINE_LENGTH
, NULL
);
1819 if (len
== GS_ESCAPE
)
1821 else if (strcasecmp(response
, _("no")) == 0) {
1822 print_warning(_("Did not write partition table to disk"));
1824 } else if (strcasecmp(response
, _("yes")) == 0)
1827 print_warning(_("Please enter `yes' or `no'"));
1831 print_warning(_("Writing partition table to disk..."));
1835 read_sector(buffer
.c
.b
, 0);
1836 fill_primary_table(&buffer
);
1837 write_sector(buffer
.c
.b
, 0);
1839 for (i
= 0; i
< num_parts
; i
++)
1840 if (IS_LOGICAL(p_info
[i
].num
)) {
1841 read_sector(buffer
.c
.b
, p_info
[i
].first_sector
);
1842 fill_logical_table(&buffer
, &(p_info
[i
]));
1843 write_sector(buffer
.c
.b
, p_info
[i
].first_sector
);
1849 if (!ioctl(fd
,BLKRRPART
))
1856 print_warning(_("Wrote partition table to disk"));
1858 print_warning(_("Wrote partition table, but re-read table failed. Reboot to update table."));
1860 print_warning(_("Wrote partition table to disk"));
1862 /* Check: unique bootable primary partition? */
1864 for (i
= 0; i
< num_parts
; i
++)
1865 if (IS_PRIMARY(i
) && p_info
[i
].flags
== ACTIVE_FLAG
)
1868 print_warning(_("No primary partitions are marked bootable. DOS MBR cannot boot this."));
1870 print_warning(_("More than one primary partition is marked bootable. DOS MBR cannot boot this."));
1874 fp_printf(FILE *fp
, char *format
, ...) {
1879 va_start(args
, format
);
1880 vsnprintf(buf
, sizeof(buf
), format
, args
);
1884 /* The following works best if the string to be printed has at
1885 most only one newline. */
1887 getyx(stdscr
, y
, x
);
1888 if (y
>= COMMAND_LINE_Y
-2) {
1894 fprintf(fp
, "%s", buf
);
1897 #define MAX_PER_LINE 16
1899 print_file_buffer(FILE *fp
, char *buffer
) {
1902 for (i
= 0, l
= 0; i
< SECTOR_SIZE
; i
++, l
++) {
1904 fp_printf(fp
, "0x%03X:", i
);
1905 fp_printf(fp
, " %02X", (unsigned char) buffer
[i
]);
1906 if (l
== MAX_PER_LINE
- 1) {
1907 fp_printf(fp
, "\n");
1912 fp_printf(fp
, "\n");
1913 fp_printf(fp
, "\n");
1917 print_raw_table(void) {
1919 partition_table buffer
;
1920 char fname
[LINE_LENGTH
];
1927 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1928 _("Enter filename or press RETURN to display on screen: "));
1930 if ((to_file
= get_string(fname
, LINE_LENGTH
, NULL
)) < 0)
1934 if ((fp
= fopen(fname
, "w")) == NULL
) {
1935 char errstr
[LINE_LENGTH
];
1936 snprintf(errstr
, sizeof(errstr
),
1937 _("Cannot open file '%s'"), fname
);
1938 print_warning(errstr
);
1948 fp_printf(fp
, _("Disk Drive: %s\n"), disk_device
);
1950 fp_printf(fp
, _("Sector 0:\n"));
1951 read_sector(buffer
.c
.b
, 0);
1952 fill_primary_table(&buffer
);
1953 print_file_buffer(fp
, buffer
.c
.b
);
1955 for (i
= 0; i
< num_parts
; i
++)
1956 if (IS_LOGICAL(p_info
[i
].num
)) {
1957 fp_printf(fp
, _("Sector %d:\n"), p_info
[i
].first_sector
);
1958 read_sector(buffer
.c
.b
, p_info
[i
].first_sector
);
1959 fill_logical_table(&buffer
, &(p_info
[i
]));
1960 print_file_buffer(fp
, buffer
.c
.b
);
1972 print_p_info_entry(FILE *fp
, partition_info
*p
) {
1976 if (p
->id
== UNUSABLE
)
1977 fp_printf(fp
, _(" None "));
1978 else if (p
->id
== FREE_SPACE
&& p
->num
== PRI_OR_LOG
)
1979 fp_printf(fp
, _(" Pri/Log"));
1980 else if (p
->id
== FREE_SPACE
&& p
->num
== PRIMARY
)
1981 fp_printf(fp
, _(" Primary"));
1982 else if (p
->id
== FREE_SPACE
&& p
->num
== LOGICAL
)
1983 fp_printf(fp
, _(" Logical"));
1985 fp_printf(fp
, "%2d %-7.7s", p
->num
+1,
1986 IS_LOGICAL(p
->num
) ? _("Logical") : _("Primary"));
1990 fp_printf(fp
, "%11lld%c", p
->first_sector
,
1991 ((p
->first_sector
/cylinder_size
) !=
1992 ((float)p
->first_sector
/cylinder_size
) ?
1995 fp_printf(fp
, "%11lld%c", p
->last_sector
,
1996 (((p
->last_sector
+1)/cylinder_size
) !=
1997 ((float)(p
->last_sector
+1)/cylinder_size
) ?
2000 fp_printf(fp
, "%6ld%c", p
->offset
,
2001 ((((p
->first_sector
== 0 || IS_LOGICAL(p
->num
)) &&
2002 (p
->offset
!= sectors
)) ||
2003 (p
->first_sector
!= 0 && IS_PRIMARY(p
->num
) &&
2007 size
= p
->last_sector
- p
->first_sector
+ 1;
2008 fp_printf(fp
, "%11lld%c", size
,
2009 ((size
/cylinder_size
) != ((float)size
/cylinder_size
) ?
2012 /* fp_printf(fp, " "); */
2014 if (p
->id
== UNUSABLE
)
2015 sprintf(part_str
, "%.15s", _("Unusable"));
2016 else if (p
->id
== FREE_SPACE
)
2017 sprintf(part_str
, "%.15s", _("Free Space"));
2018 else if (partition_type_name(p
->id
))
2019 sprintf(part_str
, "%.15s (%02X)", partition_type_name(p
->id
), p
->id
);
2021 sprintf(part_str
, "%.15s (%02X)", _("Unknown"), p
->id
);
2022 fp_printf(fp
, "%-20.20s", part_str
);
2026 if (p
->flags
== ACTIVE_FLAG
)
2027 fp_printf(fp
, _("Boot"), p
->flags
);
2028 else if (p
->flags
!= 0)
2029 fp_printf(fp
, _("(%02X)"), p
->flags
);
2031 fp_printf(fp
, _("None"), p
->flags
);
2033 fp_printf(fp
, "\n");
2037 print_p_info(void) {
2038 char fname
[LINE_LENGTH
];
2040 int i
, to_file
, pext
= is_extended(ext_info
.id
);
2046 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2047 _("Enter filename or press RETURN to display on screen: "));
2049 if ((to_file
= get_string(fname
, LINE_LENGTH
, NULL
)) < 0)
2053 if ((fp
= fopen(fname
, "w")) == NULL
) {
2054 char errstr
[LINE_LENGTH
];
2055 sprintf(errstr
, _("Cannot open file '%s'"), fname
);
2056 print_warning(errstr
);
2066 fp_printf(fp
, _("Partition Table for %s\n"), disk_device
);
2067 fp_printf(fp
, "\n");
2068 fp_printf(fp
, _(" First Last\n"));
2069 fp_printf(fp
, _(" # Type Sector Sector Offset Length Filesystem Type (ID) Flag\n"));
2070 fp_printf(fp
, _("-- ------- ----------- ----------- ------ ----------- -------------------- ----\n"));
2072 for (i
= 0; i
< num_parts
; i
++) {
2073 if (pext
&& (p_info
[i
].first_sector
>= ext_info
.first_sector
)) {
2074 print_p_info_entry(fp
,&ext_info
);
2077 print_p_info_entry(fp
, &(p_info
[i
]));
2089 print_part_entry(FILE *fp
, int num
, partition_info
*pi
) {
2090 long long first
= 0, start
= 0, end
= 0, size
= 0;
2091 unsigned char ss
, es
, sh
, eh
;
2093 int flags
= 0, id
= 0;
2095 ss
= sh
= es
= eh
= 0;
2102 if (IS_LOGICAL(num
))
2105 first
= pi
->first_sector
+ pi
->offset
;
2107 start
= pi
->first_sector
+ pi
->offset
;
2108 end
= pi
->last_sector
;
2109 size
= end
- start
+ 1;
2111 set_hsc0(&sh
, &ss
, &sc
, start
);
2112 set_hsc0(&eh
, &es
, &ec
, end
);
2115 fp_printf(fp
, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %11lld %11lld\n",
2116 num
+1, flags
, sh
, ss
, sc
, id
, eh
, es
, ec
, first
, size
);
2121 print_part_table(void) {
2123 char fname
[LINE_LENGTH
];
2130 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2131 _("Enter filename or press RETURN to display on screen: "));
2133 if ((to_file
= get_string(fname
, LINE_LENGTH
, NULL
)) < 0)
2137 if ((fp
= fopen(fname
, "w")) == NULL
) {
2138 char errstr
[LINE_LENGTH
];
2139 sprintf(errstr
, _("Cannot open file '%s'"), fname
);
2140 print_warning(errstr
);
2150 fp_printf(fp
, _("Partition Table for %s\n"), disk_device
);
2151 fp_printf(fp
, "\n");
2152 /* Three-line heading. Read "Start Sector" etc vertically. */
2153 fp_printf(fp
, _(" ---Starting--- ----Ending---- Start Number of\n"));
2154 fp_printf(fp
, _(" # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"));
2155 fp_printf(fp
, _("-- ----- ---- ---- ---- ---- ---- ---- ---- ----------- -----------\n"));
2157 for (i
= 0; i
< 4; i
++) {
2159 j
< num_parts
&& (p_info
[j
].id
<= 0 || p_info
[j
].num
!= i
);
2161 if (j
< num_parts
) {
2162 print_part_entry(fp
, i
, &(p_info
[j
]));
2163 } else if (is_extended(ext_info
.id
) && ext_info
.num
== i
) {
2164 print_part_entry(fp
, i
, &ext_info
);
2166 print_part_entry(fp
, i
, NULL
);
2170 for (i
= 0; i
< num_parts
; i
++)
2171 if (IS_LOGICAL(p_info
[i
].num
))
2172 print_part_entry(fp
, p_info
[i
].num
, &(p_info
[i
]));
2183 print_tables(void) {
2186 static struct MenuItem menuFormat
[]=
2188 { 'r', N_("Raw"), N_("Print the table using raw data format") },
2189 { 's', N_("Sectors"), N_("Print the table ordered by sectors") },
2190 { 't', N_("Table"), N_("Just print the partition table") },
2191 { ESC
, N_("Cancel"), N_("Don't print the table") },
2196 switch ( toupper(menuSimple( menuFormat
, 2)) ) {
2215 #define END_OF_HELP "EOHS!"
2217 display_help(void) {
2218 char *help_text
[] = {
2219 N_("Help Screen for cfdisk"),
2221 N_("This is cfdisk, a curses based disk partitioning program, which"),
2222 N_("allows you to create, delete and modify partitions on your hard"),
2225 N_("Copyright (C) 1994-1999 Kevin E. Martin & aeb"),
2227 N_("Command Meaning"),
2228 N_("------- -------"),
2229 N_(" b Toggle bootable flag of the current partition"),
2230 N_(" d Delete the current partition"),
2231 N_(" g Change cylinders, heads, sectors-per-track parameters"),
2232 N_(" WARNING: This option should only be used by people who"),
2233 N_(" know what they are doing."),
2234 N_(" h Print this screen"),
2235 N_(" m Maximize disk usage of the current partition"),
2236 N_(" Note: This may make the partition incompatible with"),
2237 N_(" DOS, OS/2, ..."),
2238 N_(" n Create new partition from free space"),
2239 N_(" p Print partition table to the screen or to a file"),
2240 N_(" There are several different formats for the partition"),
2241 N_(" that you can choose from:"),
2242 N_(" r - Raw data (exactly what would be written to disk)"),
2243 N_(" s - Table ordered by sectors"),
2244 N_(" t - Table in raw format"),
2245 N_(" q Quit program without writing partition table"),
2246 N_(" t Change the filesystem type"),
2247 N_(" u Change units of the partition size display"),
2248 N_(" Rotates through MB, sectors and cylinders"),
2249 N_(" W Write partition table to disk (must enter upper case W)"),
2250 N_(" Since this might destroy data on the disk, you must"),
2251 N_(" either confirm or deny the write by entering `yes' or"),
2253 N_("Up Arrow Move cursor to the previous partition"),
2254 N_("Down Arrow Move cursor to the next partition"),
2255 N_("CTRL-L Redraws the screen"),
2256 N_(" ? Print this screen"),
2258 N_("Note: All of the commands can be entered with either upper or lower"),
2259 N_("case letters (except for Writes)."),
2268 while (strcmp(help_text
[cur_line
], END_OF_HELP
)) {
2269 if (help_text
[cur_line
][0])
2270 fp_printf(fp
, "%s\n", _(help_text
[cur_line
]));
2272 fp_printf(fp
, "\n");
2279 change_geometry(void) {
2280 int ret_val
= FALSE
;
2282 char def
[LINE_LENGTH
];
2283 char response
[LINE_LENGTH
];
2288 static struct MenuItem menuGeometry
[]=
2290 { 'c', N_("Cylinders"), N_("Change cylinder geometry") },
2291 { 'h', N_("Heads"), N_("Change head geometry") },
2292 { 's', N_("Sectors"), N_("Change sector geometry") },
2293 { 'd', N_("Done"), N_("Done with changing geometry") },
2296 move(COMMAND_LINE_Y
, COMMAND_LINE_X
);
2302 switch (toupper( menuSimple(menuGeometry
, 3) )) {
2304 sprintf(def
, "%llu", actual_size
/cylinder_size
);
2305 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2306 _("Enter the number of cylinders: "));
2307 i
= get_string(response
, LINE_LENGTH
, def
);
2308 if (i
== GS_DEFAULT
) {
2309 user_cylinders
= actual_size
/cylinder_size
;
2312 tmp_val
= atoll(response
);
2314 user_cylinders
= tmp_val
;
2317 print_warning(_("Illegal cylinders value"));
2321 sprintf(def
, "%d", heads
);
2322 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2323 _("Enter the number of heads: "));
2324 if (get_string(response
, LINE_LENGTH
, def
) > 0) {
2325 tmp_val
= atoll(response
);
2326 if (tmp_val
> 0 && tmp_val
<= MAX_HEADS
) {
2327 user_heads
= tmp_val
;
2330 print_warning(_("Illegal heads value"));
2334 sprintf(def
, "%d", sectors
);
2335 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2336 _("Enter the number of sectors per track: "));
2337 if (get_string(response
, LINE_LENGTH
, def
) > 0) {
2338 tmp_val
= atoll(response
);
2339 if (tmp_val
> 0 && tmp_val
<= MAX_SECTORS
) {
2340 user_sectors
= tmp_val
;
2343 print_warning(_("Illegal sectors value"));
2356 decide_on_geometry();
2364 disk_end
= total_size
-1;
2366 if (p_info
[num_parts
-1].last_sector
> disk_end
) {
2367 while (p_info
[num_parts
-1].first_sector
> disk_end
) {
2368 if (p_info
[num_parts
-1].id
== FREE_SPACE
||
2369 p_info
[num_parts
-1].id
== UNUSABLE
)
2370 remove_part(num_parts
-1);
2372 del_part(num_parts
-1);
2375 p_info
[num_parts
-1].last_sector
= disk_end
;
2377 if (ext_info
.last_sector
> disk_end
)
2378 ext_info
.last_sector
= disk_end
;
2379 } else if (p_info
[num_parts
-1].last_sector
< disk_end
) {
2380 if (p_info
[num_parts
-1].id
== FREE_SPACE
||
2381 p_info
[num_parts
-1].id
== UNUSABLE
) {
2382 p_info
[num_parts
-1].last_sector
= disk_end
;
2384 insert_empty_part(num_parts
,
2385 p_info
[num_parts
-1].last_sector
+1,
2390 /* Make sure the partitions are correct */
2399 char id
[LINE_LENGTH
], def
[LINE_LENGTH
];
2401 int num_across
, num_down
;
2402 int len
, new_id
= ((p_info
[i
].id
== LINUX
) ? LINUX_SWAP
: LINUX
);
2403 int y_start
, y_end
, row
, row_min
, row_max
, row_offset
, j
, needmore
;
2405 for (j
= 1; i386_sys_types
[j
].name
; j
++) ;
2406 num_types
= j
-1; /* do not count the Empty type */
2408 num_across
= COLS
/COL_ID_WIDTH
;
2409 num_down
= (((float)num_types
)/num_across
+ 1);
2410 y_start
= COMMAND_LINE_Y
- 1 - num_down
;
2413 y_end
= COMMAND_LINE_Y
- 2;
2415 if (y_start
> DISK_TABLE_START
+cur_part
+4)
2416 y_start
= DISK_TABLE_START
+cur_part
+4;
2417 y_end
= y_start
+ num_down
- 1;
2421 row_max
= COMMAND_LINE_Y
- 2;
2424 for (j
= y_start
- 1; j
<= y_end
+ 1; j
++) {
2429 for (j
= 1; i386_sys_types
[j
].name
; j
++) {
2430 row
= y_start
+ (j
-1) % num_down
- row_offset
;
2431 if (row
>= row_min
&& row
<= row_max
) {
2432 move(row
, ((j
-1)/num_down
)*COL_ID_WIDTH
+ 1);
2433 printw("%02X %-20.20s",
2434 i386_sys_types
[j
].type
,
2435 i386_sys_types
[j
].name
);
2442 row_offset
+= (row_max
- row_min
+ 1);
2445 sprintf(def
, "%02X", new_id
);
2446 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
, _("Enter filesystem type: "));
2447 if ((len
= get_string(id
, 2, def
)) <= 0 && len
!= GS_DEFAULT
)
2450 if (len
!= GS_DEFAULT
) {
2451 if (!isxdigit(id
[0]))
2453 new_id
= (isdigit(id
[0]) ? id
[0] - '0' : tolower(id
[0]) - 'a' + 10);
2455 if (isxdigit(id
[1]))
2456 new_id
= new_id
*16 +
2457 (isdigit(id
[1]) ? id
[1] - '0' : tolower(id
[1]) - 'a' + 10);
2464 print_warning(_("Cannot change FS Type to empty"));
2465 else if (is_extended(new_id
))
2466 print_warning(_("Cannot change FS Type to extended"));
2468 p_info
[i
].id
= new_id
;
2472 draw_partition(int i
) {
2474 int y
= i
+ DISK_TABLE_START
+ 2 - (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
;
2479 if (!arrow_cursor
) {
2481 for (j
= 0; j
< COLS
; j
++)
2485 if (p_info
[i
].id
> 0) {
2486 char *dbn
= my_basename(disk_device
);
2487 int l
= strlen(dbn
);
2488 int digit_last
= isdigit(dbn
[l
-1]);
2490 mvprintw(y
, NAME_START
,
2491 "%s%s%d", dbn
, (digit_last
? "p" : ""),
2493 if (p_info
[i
].flags
) {
2494 if (p_info
[i
].flags
== ACTIVE_FLAG
)
2495 mvaddstr(y
, FLAGS_START
, _("Boot"));
2497 mvprintw(y
, FLAGS_START
, _("Unk(%02X)"), p_info
[i
].flags
);
2498 if (p_info
[i
].first_sector
== 0 || IS_LOGICAL(p_info
[i
].num
)) {
2499 if (p_info
[i
].offset
!= sectors
)
2502 if (p_info
[i
].offset
!= 0)
2506 if (p_info
[i
].first_sector
== 0 || IS_LOGICAL(p_info
[i
].num
)) {
2507 if (p_info
[i
].offset
!= sectors
)
2508 mvaddstr(y
, FLAGS_START
, _("NC"));
2510 if (p_info
[i
].offset
!= 0)
2511 mvaddstr(y
, FLAGS_START
, _("NC"));
2515 mvaddstr(y
, PTYPE_START
,
2516 (p_info
[i
].id
== UNUSABLE
? "" :
2517 (IS_LOGICAL(p_info
[i
].num
) ? _("Logical") :
2518 (p_info
[i
].num
>= 0 ? _("Primary") :
2519 (p_info
[i
].num
== PRI_OR_LOG
? _("Pri/Log") :
2520 (p_info
[i
].num
== PRIMARY
? _("Primary") : _("Logical")))))));
2522 t
= partition_type_text(i
);
2524 mvaddstr(y
, FSTYPE_START
, t
);
2526 mvprintw(y
, FSTYPE_START
, _("Unknown (%02X)"), p_info
[i
].id
);
2528 if (p_info
[i
].volume_label
[0]) {
2529 int l
= strlen(p_info
[i
].volume_label
);
2530 int s
= SIZE_START
-5-l
;
2531 mvprintw(y
, (s
> LABEL_START
) ? LABEL_START
: s
,
2532 " [%s] ", p_info
[i
].volume_label
);
2535 size
= p_info
[i
].last_sector
- p_info
[i
].first_sector
+ 1;
2536 fsize
= (double) size
* SECTOR_SIZE
;
2537 if (display_units
== SECTORS
)
2538 mvprintw(y
, SIZE_START
, "%11lld", size
);
2539 else if (display_units
== CYLINDERS
)
2540 mvprintw(y
, SIZE_START
, "%11lld", size
/cylinder_size
);
2541 else if (display_units
== MEGABYTES
)
2542 mvprintw(y
, SIZE_START
, "%11.2f", ceiling((100*fsize
)/(K
*K
))/100);
2543 else if (display_units
== GIGABYTES
)
2544 mvprintw(y
, SIZE_START
, "%11.2f", ceiling((100*fsize
)/(K
*K
*K
))/100);
2545 if (size
% cylinder_size
!= 0 ||
2546 p_info
[i
].first_sector
% cylinder_size
!= 0)
2547 mvprintw(y
, COLUMNS
-1, "*");
2553 NAME_START
= (((float)NAME_START
)/COLUMNS
)*COLS
;
2554 FLAGS_START
= (((float)FLAGS_START
)/COLUMNS
)*COLS
;
2555 PTYPE_START
= (((float)PTYPE_START
)/COLUMNS
)*COLS
;
2556 FSTYPE_START
= (((float)FSTYPE_START
)/COLUMNS
)*COLS
;
2557 LABEL_START
= (((float)LABEL_START
)/COLUMNS
)*COLS
;
2558 SIZE_START
= (((float)SIZE_START
)/COLUMNS
)*COLS
;
2559 COMMAND_LINE_X
= (((float)COMMAND_LINE_X
)/COLUMNS
)*COLS
;
2561 COMMAND_LINE_Y
= LINES
- 4;
2562 WARNING_START
= LINES
- 2;
2564 if ((NUM_ON_SCREEN
= COMMAND_LINE_Y
- DISK_TABLE_START
- 3) <= 0)
2577 line
= (char *) xmalloc((COLS
+1)*sizeof(char));
2579 if (warning_last_time
) {
2580 for (i
= 0; i
< COLS
; i
++) {
2581 move(WARNING_START
, i
);
2589 if (warning_last_time
)
2590 mvaddstr(WARNING_START
, 0, line
);
2593 sprintf(line
, "cfdisk %s", VERSION
);
2594 mvaddstr(HEADER_START
, (COLS
-strlen(line
))/2, line
);
2595 sprintf(line
, _("Disk Drive: %s"), disk_device
);
2596 mvaddstr(HEADER_START
+2, (COLS
-strlen(line
))/2, line
);
2598 long long bytes
= actual_size
*(long long) SECTOR_SIZE
;
2599 long long megabytes
= bytes
/1000000;
2600 if (megabytes
< 10000)
2601 sprintf(line
, _("Size: %lld bytes, %lld MB"),
2604 sprintf(line
, _("Size: %lld bytes, %lld.%lld GB"),
2605 bytes
, megabytes
/1000, (megabytes
/100)%10);
2607 mvaddstr(HEADER_START
+3, (COLS
-strlen(line
))/2, line
);
2608 sprintf(line
, _("Heads: %d Sectors per Track: %d Cylinders: %lld"),
2609 heads
, sectors
, cylinders
);
2610 mvaddstr(HEADER_START
+4, (COLS
-strlen(line
))/2, line
);
2612 mvaddstr(DISK_TABLE_START
, NAME_START
, _("Name"));
2613 mvaddstr(DISK_TABLE_START
, FLAGS_START
, _("Flags"));
2614 mvaddstr(DISK_TABLE_START
, PTYPE_START
-1, _("Part Type"));
2615 mvaddstr(DISK_TABLE_START
, FSTYPE_START
, _("FS Type"));
2616 mvaddstr(DISK_TABLE_START
, LABEL_START
+1, _("[Label]"));
2617 if (display_units
== SECTORS
)
2618 mvaddstr(DISK_TABLE_START
, SIZE_START
, _(" Sectors"));
2619 else if (display_units
== CYLINDERS
)
2620 mvaddstr(DISK_TABLE_START
, SIZE_START
, _(" Cylinders"));
2621 else if (display_units
== MEGABYTES
)
2622 mvaddstr(DISK_TABLE_START
, SIZE_START
, _(" Size (MB)"));
2623 else if (display_units
== GIGABYTES
)
2624 mvaddstr(DISK_TABLE_START
, SIZE_START
, _(" Size (GB)"));
2626 move(DISK_TABLE_START
+1, 1);
2627 for (i
= 1; i
< COLS
-1; i
++)
2630 if (NUM_ON_SCREEN
>= num_parts
)
2631 for (i
= 0; i
< num_parts
; i
++)
2634 for (i
= (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
;
2635 i
< NUM_ON_SCREEN
+ (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
&&
2644 draw_cursor(int move
) {
2645 if (move
!= 0 && (cur_part
+ move
< 0 || cur_part
+ move
>= num_parts
))
2649 mvaddstr(DISK_TABLE_START
+ cur_part
+ 2
2650 - (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
, 0, " ");
2652 draw_partition(cur_part
);
2656 if (((cur_part
- move
)/NUM_ON_SCREEN
)*NUM_ON_SCREEN
!=
2657 (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
)
2661 mvaddstr(DISK_TABLE_START
+ cur_part
+ 2
2662 - (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
, 0, "-->");
2665 draw_partition(cur_part
);
2673 do_curses_fdisk(void) {
2677 static struct MenuItem menuMain
[] = {
2678 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
2679 { 'd', N_("Delete"), N_("Delete the current partition") },
2680 { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") },
2681 { 'h', N_("Help"), N_("Print help screen") },
2682 { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") },
2683 { 'n', N_("New"), N_("Create new partition from free space") },
2684 { 'p', N_("Print"), N_("Print partition table to the screen or to a file") },
2685 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
2686 { 't', N_("Type"), N_("Change the filesystem type (DOS, Linux, OS/2 and so on)") },
2687 { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") },
2688 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
2695 old_SIGINT
= signal(SIGINT
, die
);
2696 old_SIGTERM
= signal(SIGTERM
, die
);
2698 signal(SIGINT
, old_SIGINT
);
2699 signal(SIGTERM
, old_SIGTERM
);
2713 (void)draw_cursor(0);
2715 if (p_info
[cur_part
].id
== FREE_SPACE
) {
2716 s
= ((opentype
== O_RDWR
) ? "hnpquW" : "hnpqu");
2717 command
= menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuMain
, 8,
2718 s
, MENU_HORIZ
| MENU_BUTTON
| MENU_ACCEPT_OTHERS
, 0);
2719 } else if (p_info
[cur_part
].id
> 0) {
2720 s
= ((opentype
== O_RDWR
) ? "bdhmpqtuW" : "bdhmpqtu");
2721 command
= menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuMain
, 8,
2722 s
, MENU_HORIZ
| MENU_BUTTON
| MENU_ACCEPT_OTHERS
, 0);
2724 s
= ((opentype
== O_RDWR
) ? "hpquW" : "hpqu");
2725 command
= menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuMain
, 8,
2726 s
, MENU_HORIZ
| MENU_BUTTON
| MENU_ACCEPT_OTHERS
, 0);
2728 switch ( command
) {
2731 if (p_info
[cur_part
].id
> 0)
2732 p_info
[cur_part
].flags
^= 0x80;
2734 print_warning(_("Cannot make this partition bootable"));
2738 if (p_info
[cur_part
].id
> 0) {
2740 if (cur_part
>= num_parts
)
2741 cur_part
= num_parts
- 1;
2744 print_warning(_("Cannot delete an empty partition"));
2748 if (change_geometry())
2753 if (p_info
[cur_part
].id
> 0) {
2754 if (p_info
[cur_part
].first_sector
== 0 ||
2755 IS_LOGICAL(p_info
[cur_part
].num
)) {
2756 if (p_info
[cur_part
].offset
== sectors
)
2757 p_info
[cur_part
].offset
= 1;
2759 p_info
[cur_part
].offset
= sectors
;
2761 } else if (p_info
[cur_part
].offset
!= 0)
2762 p_info
[cur_part
].offset
= 0;
2764 print_warning(_("Cannot maximize this partition"));
2766 print_warning(_("Cannot maximize this partition"));
2770 if (p_info
[cur_part
].id
== FREE_SPACE
) {
2773 } else if (p_info
[cur_part
].id
== UNUSABLE
)
2774 print_warning(_("This partition is unusable"));
2776 print_warning(_("This partition is already in use"));
2789 if (p_info
[cur_part
].id
> 0) {
2790 change_id(cur_part
);
2793 print_warning(_("Cannot change the type of an empty partition"));
2797 if (display_units
== GIGABYTES
)
2798 display_units
= MEGABYTES
;
2799 else if (display_units
== MEGABYTES
)
2800 display_units
= SECTORS
;
2801 else if (display_units
== SECTORS
)
2802 display_units
= CYLINDERS
;
2803 else if (display_units
== CYLINDERS
)
2804 display_units
= MEGABYTES
; /* not yet GIGA */
2816 case MENU_UP
: /* Up arrow */
2817 if (!draw_cursor(-1))
2820 print_warning(_("No more partitions"));
2822 case MENU_DOWN
: /* Down arrow */
2823 if (!draw_cursor(1))
2826 print_warning(_("No more partitions"));
2833 print_warning(_("Illegal command"));
2834 putchar(BELL
); /* CTRL-G */
2843 fprintf(stderr
, _("Copyright (C) 1994-2002 Kevin E. Martin & aeb\n"));
2847 usage(char *prog_name
) {
2848 /* Unfortunately, xgettext does not handle multi-line strings */
2849 /* so, let's use explicit \n's instead */
2850 fprintf(stderr
, _("\n"
2854 "Print partition table:\n"
2855 " %s -P {r|s|t} [options] device\n"
2856 "Interactive use:\n"
2857 " %s [options] device\n"
2860 "-a: Use arrow instead of highlighting;\n"
2861 "-z: Start with a zero partition table, instead of reading the pt from disk;\n"
2862 "-c C -h H -s S: Override the kernel's idea of the number of cylinders,\n"
2863 " the number of heads and the number of sectors/track.\n\n"),
2864 prog_name
, prog_name
, prog_name
);
2870 main(int argc
, char **argv
)
2875 setlocale(LC_ALL
, "");
2876 bindtextdomain(PACKAGE
, LOCALEDIR
);
2877 textdomain(PACKAGE
);
2879 while ((c
= getopt(argc
, argv
, "ac:gh:s:vzP:")) != -1)
2882 arrow_cursor
= TRUE
;
2885 user_cylinders
= cylinders
= atoll(optarg
);
2886 if (cylinders
<= 0) {
2887 fprintf(stderr
, "%s: %s\n", argv
[0], _("Illegal cylinders value"));
2892 use_partition_table_geometry
= TRUE
;
2895 user_heads
= heads
= atoi(optarg
);
2896 if (heads
<= 0 || heads
> MAX_HEADS
) {
2897 fprintf(stderr
, "%s: %s\n", argv
[0], _("Illegal heads value"));
2902 user_sectors
= sectors
= atoi(optarg
);
2903 if (sectors
<= 0 || sectors
> MAX_SECTORS
) {
2904 fprintf(stderr
, "%s: %s\n", argv
[0], _("Illegal sectors value"));
2909 fprintf(stderr
, "cfdisk %s\n", VERSION
);
2916 len
= strlen(optarg
);
2917 for (i
= 0; i
< len
; i
++) {
2918 switch (optarg
[i
]) {
2920 print_only
|= PRINT_RAW_TABLE
;
2923 print_only
|= PRINT_SECTOR_TABLE
;
2926 print_only
|= PRINT_PARTITION_TABLE
;
2939 if (argc
-optind
== 1)
2940 disk_device
= argv
[optind
];
2941 else if (argc
-optind
!= 0) {
2944 } else if ((fd
= open(DEFAULT_DEVICE
, O_RDONLY
)) < 0)
2945 disk_device
= ALTERNATE_DEVICE
;
2950 if (print_only
& PRINT_RAW_TABLE
)
2952 if (print_only
& PRINT_SECTOR_TABLE
)
2954 if (print_only
& PRINT_PARTITION_TABLE
)