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-n: aeb@cwi.nl
33 * Recognition of NTFS / HPFS difference inspired by patches
34 * from Marty Leisner <leisner@sdsp.mc.xerox.com>
35 * Exit codes by Enrique Zanardi <ezanardi@ull.es>:
37 * 1: command line error
38 * 2: hardware problems [BAD_SEEK, BAD_READ, BAD_WRITE or BAD_OPEN].
39 * 3: ioctl(fd, HDIO_GETGEO,...) failed [BAD_GEOMETRY].
40 * 4: bad partition table on disk. [BAD_PRIMARY or BAD_LOGICAL].
42 ****************************************************************************/
66 #include <sys/ioctl.h>
67 #include <linux/types.h>
68 #include <linux/hdreg.h>
69 #include <linux/fs.h> /* for BLKRRPART */
71 #if defined(__GNUC__) || defined(HAS_LONG_LONG)
72 typedef long long ext2_loff_t
;
74 typedef long ext2_loff_t
;
77 extern ext2_loff_t
ext2_llseek(unsigned int fd
, ext2_loff_t offset
,
80 #define VERSION "0.8n"
82 #define DEFAULT_DEVICE "/dev/hda"
83 #define ALTERNATE_DEVICE "/dev/sda"
85 #define LINE_LENGTH 80
86 #define MAXIMUM_PARTS 60
88 #define SECTOR_SIZE 512
90 #define MAX_CYLINDERS 65535
92 #define MAX_SECTORS 63
94 #define ACTIVE_FLAG 0x80
95 #define PART_TABLE_FLAG0 0x55
96 #define PART_TABLE_FLAG1 0xAA
99 #define FREE_SPACE 0x00
100 #define DOS_EXTENDED 0x05
101 #define OS2_OR_NTFS 0x07
102 #define WIN98_EXTENDED 0x0f
103 #define LINUX_EXTENDED 0x85
104 #define LINUX_MINIX 0x81
105 #define LINUX_SWAP 0x82
108 #define ADD_EXISTS "This partition is already in use"
109 #define ADD_UNUSABLE "This partition is unusable"
110 #define DEL_EMPTY "Cannot delete an empty partition"
111 #define ID_EMPTY "Cannot change FS Type to empty"
112 #define ID_EXT "Cannot change FS Type to extended"
113 #define NEED_EXT "No room to create the extended partition"
114 #define NO_FLAGS "Cannot make this partition bootable"
115 #define NO_MORE_PARTS "No more partitions"
116 #define PRINT_OPEN_ERR "Cannot open file '%s'"
117 #define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions"
118 #define TYPE_EMPTY "Cannot change the type of an empty partition"
119 #define BAD_COMMAND "Illegal command"
120 #define MAX_UNMAXABLE "Cannot maximize this partition"
121 #define BAD_OPEN "Cannot open disk drive"
122 #define BAD_SEEK "Cannot seek on disk drive"
123 #define BAD_READ "Cannot read disk drive"
124 #define BAD_WRITE "Cannot write disk drive"
125 #define BAD_GEOMETRY "Cannot read disk drive geometry"
126 #define BAD_PRIMARY "Bad primary partition"
127 #define BAD_LOGICAL "Bad logical partition"
128 #define BAD_CYLINDERS "Illegal cylinders value"
129 #define BAD_HEADS "Illegal heads value"
130 #define BAD_SECTORS "Illegal sectors value"
131 #define READONLY_WARN "Opened disk read-only - you have no permission to write"
132 #define WRITE_WARN "Warning!! This may destroy data on your disk!"
133 #define YES_NO "Please enter `yes' or `no'"
134 #define WRITING_PART "Writing partition table to disk..."
135 #define YES_WRITE "Wrote partition table to disk"
136 #define NO_WRITE "Did not write partition table to disk"
137 #define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table."
138 #define NOT_DOS_MBR_BOOTABLE "Not precisely one primary partition is bootable. DOS MBR cannot boot this."
140 #define PRI_OR_LOG -1
144 #define COL_ID_WIDTH 20
151 #define REDRAWKEY '\014'
158 #define GS_DEFAULT -1
161 #define PRINT_RAW_TABLE 1
162 #define PRINT_SECTOR_TABLE 2
163 #define PRINT_PARTITION_TABLE 4
165 #define IS_PRIMARY(p) ((p) >= 0 && (p) < 4)
166 #define IS_LOGICAL(p) ((p) > 3)
168 #define round_int(d) ((double)((int)(d+0.5)))
169 #define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d)))
171 #define set_hsc(h,s,c,sector) \
173 s = sector % sectors + 1; \
175 h = sector % heads; \
178 s |= (sector >> 2) & 0xC0;\
181 #define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \
182 (x) == LINUX_EXTENDED)
184 #define is_dos_partition(x) ((x) == 1 || (x) == 4 || (x) == 6)
185 #define may_have_dos_label(x) (is_dos_partition(x) \
186 || (x) == 7 || (x) == 0xb || (x) == 0xc || (x) == 0xe \
187 || (x) == 0x11 || (x) == 0x14 || (x) == 0x16 || (x) == 0x17)
190 unsigned char boot_ind
; /* 0x80 - active */
191 unsigned char head
; /* starting head */
192 unsigned char sector
; /* starting sector */
193 unsigned char cyl
; /* starting cylinder */
194 unsigned char sys_ind
; /* What partition type */
195 unsigned char end_head
; /* end head */
196 unsigned char end_sector
; /* end sector */
197 unsigned char end_cyl
; /* end cylinder */
198 unsigned char start4
[4]; /* starting sector counting from 0 */
199 unsigned char size4
[4]; /* nr of sectors in partition */
202 /* start_sect and nr_sects are stored little endian on all machines */
203 /* moreover, they are not aligned correctly */
205 store4_little_endian(unsigned char *cp
, unsigned int val
) {
206 cp
[0] = (val
& 0xff);
207 cp
[1] = ((val
>> 8) & 0xff);
208 cp
[2] = ((val
>> 16) & 0xff);
209 cp
[3] = ((val
>> 24) & 0xff);
213 read4_little_endian(unsigned char *cp
) {
214 return (uint
)(cp
[0]) + ((uint
)(cp
[1]) << 8)
215 + ((uint
)(cp
[2]) << 16) + ((uint
)(cp
[3]) << 24);
219 set_start_sect(struct partition
*p
, unsigned int start_sect
) {
220 store4_little_endian(p
->start4
, start_sect
);
224 get_start_sect(struct partition
*p
) {
225 return read4_little_endian(p
->start4
);
229 set_nr_sects(struct partition
*p
, unsigned int nr_sects
) {
230 store4_little_endian(p
->size4
, nr_sects
);
234 get_nr_sects(struct partition
*p
) {
235 return read4_little_endian(p
->size4
);
241 unsigned char align
[ALIGNMENT
];
242 unsigned char b
[SECTOR_SIZE
];
245 unsigned char align
[ALIGNMENT
];
246 unsigned char buffer
[0x1BE];
247 struct partition part
[4];
248 unsigned char magicflag
[2];
253 int first_sector
; /* first sector in partition */
254 int last_sector
; /* last sector in partition */
255 int offset
; /* offset from first sector to start of data */
256 int flags
; /* active == 0x80 */
257 int id
; /* filesystem type */
258 int num
; /* number of partition -- primary vs. logical */
260 char volume_label
[LABELSZ
+1];
262 char ostype
[OSTYPESZ
+1];
264 char fstype
[FSTYPESZ
+1];
267 char *disk_device
= DEFAULT_DEVICE
;
275 int curses_started
= 0;
277 partition_info p_info
[MAXIMUM_PARTS
];
278 partition_info ext_info
;
282 int logical_sectors
[MAXIMUM_PARTS
];
284 __sighandler_t old_SIGINT
, old_SIGTERM
;
286 int arrow_cursor
= FALSE
;
287 int display_units
= MEGABYTES
;
288 int zero_table
= FALSE
;
291 /* Curses screen information */
293 int warning_last_time
= FALSE
;
296 int NUM_ON_SCREEN
= 1;
299 int HEADER_START
= 0;
300 int DISK_TABLE_START
= 5;
301 int WARNING_START
= 23;
302 int COMMAND_LINE_Y
= 21;
306 int FLAGS_START
= 16;
307 int PTYPE_START
= 28;
308 int FSTYPE_START
= 38;
309 int LABEL_START
= 54;
311 int COMMAND_LINE_X
= 5;
313 #define NUM_PART_TYPES 256
314 char *partition_type
[NUM_PART_TYPES
] = {
315 [LINUX_MINIX
] = "Linux/MINIX",
316 [LINUX_SWAP
] = "Linux Swap",
318 [FREE_SPACE
] = "Free Space",
319 [DOS_EXTENDED
]= "Extended",
320 [LINUX_EXTENDED
] = "Linux extended",
321 [0x01] = "DOS FAT12",
322 [0x02] = "XENIX root",
323 [0x03] = "XENIX usr",
324 [0x04] = "DOS FAT16",
325 [0x06] = "DOS FAT16 (big)",
326 [OS2_OR_NTFS
] = "OS/2 HPFS or NTFS",
328 [0x09] = "AIX bootable",
329 [0x0A] = "OS/2 Boot Manager",
330 [0x0B] = "Win95 FAT32",
331 [0x0C] = "Win95 FAT32 (LBA)",
332 [0x0E] = "Win95 FAT16 (LBA)",
333 [0x0F] = "Win95 Extended (LBA)",
334 [0x11] = "Hidden DOS FAT12",
335 [0x14] = "Hidden DOS FAT16",
336 [0x16] = "Hidden DOS FAT16 (big)",
337 [0x17] = "Hidden OS/2 HPFS or NTFS",
338 [0x40] = "Venix 80286",
339 [0x41] = "PPC PReP boot",
341 [0x52] = "Microport",
343 [0x64] = "Novell Netware 286",
344 [0x65] = "Novell Netware 386",
346 [0x80] = "Old MINIX",
348 [0x94] = "Amoeba BBT",
353 [0xB8] = "BSDI swap",
356 [0xE1] = "DOS access",
359 [0xF2] = "DOS secondary",
363 /* Some libc's have their own basename() */
364 char *my_basename(char *devname
)
366 char *s
= rindex(devname
, '/');
367 return s
? s
+1 : devname
;
370 char *partition_type_text(int i
)
372 if (p_info
[i
].id
== UNUSABLE
)
374 else if (p_info
[i
].id
== FREE_SPACE
)
376 else if (p_info
[i
].id
== LINUX
) {
377 if (!strcmp(p_info
[i
].fstype
, "ext2"))
381 } else if (p_info
[i
].id
== OS2_OR_NTFS
) {
382 if (!strncmp(p_info
[i
].fstype
, "HPFS", 4))
384 else if (!strncmp(p_info
[i
].ostype
, "OS2", 3))
386 else if (!p_info
[i
].ostype
)
387 return p_info
[i
].ostype
;
391 return partition_type
[p_info
[i
].id
];
400 fprintf(stderr
, "Disk has been changed.\n");
401 fprintf(stderr
, "Reboot the system to ensure the partition "
402 "table is correctly updated.\n");
404 fprintf( stderr
, "\nWARNING: If you have created or modified any\n"
405 "DOS 6.x partitions, please see the cfdisk manual\n"
406 "page for additional information.\n" );
412 int get_string(char *str
, int len
, char *def
)
431 while ((c
= getch()) != '\n' && c
!= CR
) {
442 mvaddch(y
, x
+i
, ' ');
444 } else if (use_def
) {
451 if (i
< len
&& isprint(c
)) {
471 void clear_warning(void)
475 if (!curses_started
|| !warning_last_time
)
478 move(WARNING_START
,0);
479 for (i
= 0; i
< COLS
; i
++)
482 warning_last_time
= FALSE
;
485 void print_warning(char *s
)
487 if (!curses_started
) {
488 fprintf(stderr
, "%s\n", s
);
490 mvaddstr(WARNING_START
, (COLS
-strlen(s
))/2, s
);
491 putchar(BELL
); /* CTRL-G */
493 warning_last_time
= TRUE
;
499 void fatal(char *s
, int ret
)
501 char str
[LINE_LENGTH
];
503 if (curses_started
) {
504 sprintf(str
, "FATAL ERROR: %s", s
);
505 mvaddstr(WARNING_START
, (COLS
-strlen(str
))/2, str
);
506 sprintf(str
, "Press any key to exit fdisk");
507 mvaddstr(WARNING_START
+1, (COLS
-strlen(str
))/2, str
);
508 putchar(BELL
); /* CTRL-G */
513 fprintf(stderr
, "FATAL ERROR: %s\n", s
);
525 signal(SIGINT
, old_SIGINT
);
526 signal(SIGTERM
, old_SIGTERM
);
528 SLsmg_gotorc(LINES
-1, 0);
531 mvcur(0, COLS
-1, LINES
-1, 0);
539 void read_sector(char *buffer
, int sect_num
)
541 if (ext2_llseek(fd
, ((ext2_loff_t
) sect_num
)*SECTOR_SIZE
, SEEK_SET
) < 0)
543 if (read(fd
, buffer
, SECTOR_SIZE
) != SECTOR_SIZE
)
547 void write_sector(char *buffer
, int sect_num
)
549 if (ext2_llseek(fd
, ((ext2_loff_t
) sect_num
)*SECTOR_SIZE
, SEEK_SET
) < 0)
551 if (write(fd
, buffer
, SECTOR_SIZE
) != SECTOR_SIZE
)
555 void dos_copy_to_info(char *to
, int tosz
, char *from
, int fromsz
) {
558 for(i
=0; i
<tosz
&& i
<fromsz
&& isascii(from
[i
]); i
++)
563 void get_dos_label(int i
)
566 #define DOS_OSTYPE_OFFSET 3
567 #define DOS_LABEL_OFFSET 43
568 #define DOS_FSTYPE_OFFSET 54
569 #define DOS_OSTYPE_SZ 8
570 #define DOS_LABEL_SZ 11
571 #define DOS_FSTYPE_SZ 8
574 offset
= ((ext2_loff_t
) p_info
[i
].first_sector
+ p_info
[i
].offset
)
576 if (ext2_llseek(fd
, offset
, SEEK_SET
) == offset
577 && read(fd
, §or
, sizeof(sector
)) == sizeof(sector
)) {
578 dos_copy_to_info(p_info
[i
].ostype
, OSTYPESZ
,
579 sector
+DOS_OSTYPE_OFFSET
, DOS_OSTYPE_SZ
);
580 dos_copy_to_info(p_info
[i
].volume_label
, LABELSZ
,
581 sector
+DOS_LABEL_OFFSET
, DOS_LABEL_SZ
);
582 dos_copy_to_info(p_info
[i
].fstype
, FSTYPESZ
,
583 sector
+DOS_FSTYPE_OFFSET
, DOS_FSTYPE_SZ
);
587 void get_ext2_label(int i
)
589 #define EXT2_SUPER_MAGIC 0xEF53
590 #define EXT2LABELSZ 16
591 struct ext2_super_block
{
593 unsigned char s_magic
[2];
595 char s_volume_name
[EXT2LABELSZ
];
596 char s_last_mounted
[64];
599 char *label
= sb
.s_volume_name
;
603 offset
= ((ext2_loff_t
) p_info
[i
].first_sector
+ p_info
[i
].offset
)
604 * SECTOR_SIZE
+ 1024;
605 if (ext2_llseek(fd
, offset
, SEEK_SET
) == offset
606 && read(fd
, &sb
, sizeof(sb
)) == sizeof(sb
)
607 && sb
.s_magic
[0] + 256*sb
.s_magic
[1] == EXT2_SUPER_MAGIC
) {
608 for(j
=0; j
<EXT2LABELSZ
; j
++)
609 if(!isprint(label
[j
]))
611 label
[EXT2LABELSZ
] = 0;
612 strncpy(p_info
[i
].volume_label
, label
, LABELSZ
);
613 strncpy(p_info
[i
].fstype
, "ext2", FSTYPESZ
);
617 void check_part_info(void)
619 int i
, pri
= 0, log
= 0;
621 for (i
= 0; i
< num_parts
; i
++)
622 if (p_info
[i
].id
> 0 && IS_PRIMARY(p_info
[i
].num
))
624 else if (p_info
[i
].id
> 0 && IS_LOGICAL(p_info
[i
].num
))
626 if (is_extended(ext_info
.id
)) {
630 ext_info
.first_sector
= 0;
631 ext_info
.last_sector
= 0;
634 ext_info
.id
= FREE_SPACE
;
635 ext_info
.num
= PRIMARY
;
640 for (i
= 0; i
< num_parts
; i
++)
641 if (p_info
[i
].id
== FREE_SPACE
|| p_info
[i
].id
== UNUSABLE
) {
642 if (is_extended(ext_info
.id
)) {
643 if (p_info
[i
].first_sector
>= ext_info
.first_sector
&&
644 p_info
[i
].last_sector
<= ext_info
.last_sector
) {
645 p_info
[i
].id
= FREE_SPACE
;
646 p_info
[i
].num
= LOGICAL
;
648 p_info
[i
-1].first_sector
>=
649 ext_info
.first_sector
&&
650 p_info
[i
-1].last_sector
<=
651 ext_info
.last_sector
) {
652 p_info
[i
].id
= FREE_SPACE
;
653 p_info
[i
].num
= LOGICAL
;
654 } else if (i
< num_parts
-1 &&
655 p_info
[i
+1].first_sector
>=
656 ext_info
.first_sector
&&
657 p_info
[i
+1].last_sector
<=
658 ext_info
.last_sector
) {
659 p_info
[i
].id
= FREE_SPACE
;
660 p_info
[i
].num
= LOGICAL
;
662 p_info
[i
].id
= UNUSABLE
;
663 } else /* if (!is_extended(ext_info.id)) */
664 p_info
[i
].id
= UNUSABLE
;
665 } else /* if (p_info[i].id > 0) */
666 while (0); /* Leave these alone */
667 } else { /* if (pri < 4) */
668 for (i
= 0; i
< num_parts
; i
++) {
669 if (p_info
[i
].id
== UNUSABLE
)
670 p_info
[i
].id
= FREE_SPACE
;
671 if (p_info
[i
].id
== FREE_SPACE
) {
672 if (is_extended(ext_info
.id
)) {
673 if (p_info
[i
].first_sector
>= ext_info
.first_sector
&&
674 p_info
[i
].last_sector
<= ext_info
.last_sector
)
675 p_info
[i
].num
= LOGICAL
;
677 p_info
[i
-1].first_sector
>=
678 ext_info
.first_sector
&&
679 p_info
[i
-1].last_sector
<=
680 ext_info
.last_sector
)
681 p_info
[i
].num
= PRI_OR_LOG
;
682 else if (i
< num_parts
-1 &&
683 p_info
[i
+1].first_sector
>=
684 ext_info
.first_sector
&&
685 p_info
[i
+1].last_sector
<=
686 ext_info
.last_sector
)
687 p_info
[i
].num
= PRI_OR_LOG
;
689 p_info
[i
].num
= PRIMARY
;
690 } else /* if (!is_extended(ext_info.id)) */
691 p_info
[i
].num
= PRI_OR_LOG
;
692 } else /* if (p_info[i].id > 0) */
693 while (0); /* Leave these alone */
698 void remove_part(int i
)
702 for (p
= i
; p
< num_parts
; p
++)
703 p_info
[p
] = p_info
[p
+1];
708 void insert_empty_part(int i
, int first
, int last
)
712 for (p
= num_parts
; p
> i
; p
--)
713 p_info
[p
] = p_info
[p
-1];
715 p_info
[i
].first_sector
= first
;
716 p_info
[i
].last_sector
= last
;
717 p_info
[i
].offset
= 0;
719 p_info
[i
].id
= FREE_SPACE
;
720 p_info
[i
].num
= PRI_OR_LOG
;
721 p_info
[i
].volume_label
[0] = 0;
722 p_info
[i
].fstype
[0] = 0;
723 p_info
[i
].ostype
[0] = 0;
730 int num
= p_info
[i
].num
;
732 if (i
> 0 && (p_info
[i
-1].id
== FREE_SPACE
||
733 p_info
[i
-1].id
== UNUSABLE
)) {
734 /* Merge with previous partition */
735 p_info
[i
-1].last_sector
= p_info
[i
].last_sector
;
739 if (i
< num_parts
- 1 && (p_info
[i
+1].id
== FREE_SPACE
||
740 p_info
[i
+1].id
== UNUSABLE
)) {
741 /* Merge with next partition */
742 p_info
[i
+1].first_sector
= p_info
[i
].first_sector
;
747 p_info
[i
].first_sector
= p_info
[i
-1].last_sector
+ 1;
749 p_info
[i
].first_sector
= 0;
751 if (i
< num_parts
- 1)
752 p_info
[i
].last_sector
= p_info
[i
+1].first_sector
- 1;
754 p_info
[i
].last_sector
= sectors
*heads
*cylinders
- 1;
756 p_info
[i
].offset
= 0;
758 p_info
[i
].id
= FREE_SPACE
;
759 p_info
[i
].num
= PRI_OR_LOG
;
761 if (IS_LOGICAL(num
)) {
762 /* We have a logical partition --> shrink the extended partition
763 * if (1) this is the first logical drive, or (2) this is the
764 * last logical drive; and if there are any other logical drives
765 * then renumber the ones after "num".
767 if (i
== 0 || (i
> 0 && IS_PRIMARY(p_info
[i
-1].num
))) {
768 ext_info
.first_sector
= p_info
[i
].last_sector
+ 1;
771 if (i
== num_parts
-1 ||
772 (i
< num_parts
-1 && IS_PRIMARY(p_info
[i
+1].num
)))
773 ext_info
.last_sector
= p_info
[i
].first_sector
- 1;
774 for (i
= 0; i
< num_parts
; i
++)
775 if (p_info
[i
].num
> num
)
779 /* Clean up the rest of the partitions */
783 int add_part(int num
, int id
, int flags
, int first
, int last
, int offset
,
786 int i
, pri
= 0, log
= 0;
788 if (num_parts
== MAXIMUM_PARTS
||
790 first
>= cylinders
*heads
*sectors
||
792 last
>= cylinders
*heads
*sectors
) {
793 return -1; /* bad start or end */
796 for (i
= 0; i
< num_parts
; i
++)
797 if (p_info
[i
].id
> 0 && IS_PRIMARY(p_info
[i
].num
))
799 else if (p_info
[i
].id
> 0 && IS_LOGICAL(p_info
[i
].num
))
801 if (is_extended(ext_info
.id
) && log
> 0)
804 if (IS_PRIMARY(num
)) {
806 return -1; /* no room for more */
811 for (i
= 0; i
< num_parts
&& p_info
[i
].last_sector
< first
; i
++);
813 if (i
== num_parts
|| p_info
[i
].id
!= FREE_SPACE
814 || last
> p_info
[i
].last_sector
) {
818 if (is_extended(id
)) {
819 if (ext_info
.id
!= FREE_SPACE
) {
820 return -1; /* second extended */
822 else if (IS_PRIMARY(num
)) {
823 ext_info
.first_sector
= first
;
824 ext_info
.last_sector
= last
;
825 ext_info
.offset
= offset
;
826 ext_info
.flags
= flags
;
829 ext_info
.volume_label
[0] = 0;
830 ext_info
.fstype
[0] = 0;
831 ext_info
.ostype
[0] = 0;
834 return -1; /* explicit extended logical */
838 if (IS_LOGICAL(num
)) {
839 if (!is_extended(ext_info
.id
)) {
840 print_warning("!!!! Internal error creating logical "
841 "drive with no extended partition !!!!");
843 /* We might have a logical partition outside of the extended
844 * partition's range --> we have to extend the extended
845 * partition's range to encompass this new partition, but we
846 * must make sure that there are no primary partitions between
847 * it and the closest logical drive in extended partition.
849 if (first
< ext_info
.first_sector
) {
850 if (i
< num_parts
-1 && IS_PRIMARY(p_info
[i
+1].num
)) {
851 print_warning(TWO_EXTENDEDS
);
855 ext_info
.first_sector
= 0;
856 ext_info
.offset
= first
= offset
;
858 ext_info
.first_sector
= first
;
861 } else if (last
> ext_info
.last_sector
) {
862 if (i
> 0 && IS_PRIMARY(p_info
[i
-1].num
)) {
863 print_warning(TWO_EXTENDEDS
);
866 ext_info
.last_sector
= last
;
872 if (first
!= p_info
[i
].first_sector
&&
873 !(IS_LOGICAL(num
) && first
== offset
)) {
874 insert_empty_part(i
, p_info
[i
].first_sector
, first
-1);
878 if (last
!= p_info
[i
].last_sector
)
879 insert_empty_part(i
+1, last
+1, p_info
[i
].last_sector
);
881 p_info
[i
].first_sector
= first
;
882 p_info
[i
].last_sector
= last
;
883 p_info
[i
].offset
= offset
;
884 p_info
[i
].flags
= flags
;
887 p_info
[i
].volume_label
[0] = 0;
888 p_info
[i
].fstype
[0] = 0;
889 p_info
[i
].ostype
[0] = 0;
891 if (may_have_dos_label(id
))
893 else if (id
== LINUX
)
902 int find_primary(void)
904 int num
= 0, cur
= 0;
906 while (cur
< num_parts
&& IS_PRIMARY(num
))
907 if ((p_info
[cur
].id
> 0 && p_info
[cur
].num
== num
) ||
908 (is_extended(ext_info
.id
) && ext_info
.num
== num
)) {
914 if (!IS_PRIMARY(num
))
920 int find_logical(int i
)
925 for (j
= i
; j
< num_parts
&& num
== -1; j
++)
926 if (p_info
[j
].id
> 0 && IS_LOGICAL(p_info
[j
].num
))
931 for (j
= 0; j
< num_parts
; j
++)
932 if (p_info
[j
].id
> 0 && p_info
[j
].num
== num
)
939 void inc_logical(int i
)
943 for (j
= i
; j
< num_parts
; j
++)
944 if (p_info
[j
].id
> 0 && IS_LOGICAL(p_info
[j
].num
))
948 /* Command menu support by Janne Kukonlehto <jtklehto@phoenix.oulu.fi> September 1994 */
950 /* Constants for menuType parameter of menuSelect function */
953 #define MENU_ACCEPT_OTHERS 4
954 #define MENU_BUTTON 8
955 /* Miscellenous constants */
956 #define MENU_SPACING 2
957 #define MENU_MAX_ITEMS 256 /* for simpleMenu function */
965 int key
; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */
966 char *name
; /* Item name, should be eight characters with current implementation */
967 char *desc
; /* Item description to be printed when item is selected */
971 * Actual function which prints the button bar and highlights the active button
972 * Should not be called directly. Call function menuSelect instead.
975 int menuUpdate( int y
, int x
, struct MenuItem
*menuItems
, int itemLength
,
976 char *available
, int menuType
, int current
)
978 int i
, lmargin
= x
, ymargin
= y
;
979 /* Print available buttons */
980 move( y
, x
); clrtoeol();
981 for( i
= 0; menuItems
[i
].key
; i
++ )
985 /* Search next available button */
986 while( menuItems
[i
].key
&& !strchr(available
, menuItems
[i
].key
) )
990 if( !menuItems
[i
].key
) break; /* No more menu items */
991 /* If selected item is not available and we have bypassed it,
992 make current item selected */
993 if( current
< i
&& menuItems
[current
].key
< 0 ) current
= i
;
994 /* If current item is selected, highlight it */
995 if( current
== i
) /*attron( A_REVERSE )*/ standout ();
997 lenName
= strlen( menuItems
[i
].name
);
998 if(lenName
> itemLength
)
999 print_warning("Menu item too long. Menu may look odd.");
1000 if( menuType
& MENU_BUTTON
)
1001 sprintf( buff
, "[%*s%-*s]", (itemLength
- lenName
) / 2, "",
1002 (itemLength
- lenName
+ 1) / 2 + lenName
, menuItems
[i
].name
);
1004 sprintf( buff
, "%*s%-*s", (itemLength
- lenName
) / 2, "",
1005 (itemLength
- lenName
+ 1) / 2 + lenName
, menuItems
[i
].name
);
1006 mvaddstr( y
, x
, buff
);
1007 /* Lowlight after selected item */
1008 if( current
== i
) /*attroff( A_REVERSE )*/ standend ();
1009 /* Calculate position for the next item */
1010 if( menuType
& MENU_VERT
)
1013 if( y
>= WARNING_START
)
1016 x
+= itemLength
+ MENU_SPACING
;
1017 if( menuType
& MENU_BUTTON
) x
+= 2;
1022 x
+= itemLength
+ MENU_SPACING
;
1023 if( menuType
& MENU_BUTTON
) x
+= 2;
1024 if( x
> COLUMNS
- lmargin
- 12 )
1031 /* Print the description of selected item */
1032 mvaddstr( WARNING_START
+ 1,
1033 (COLUMNS
- strlen( menuItems
[current
].desc
)) / 2,
1034 menuItems
[current
].desc
);
1038 /* This function takes a list of menu items, lets the user choose one of them *
1039 * and returns the value keyboard shortcut of the selected menu item */
1041 int menuSelect( int y
, int x
, struct MenuItem
*menuItems
, int itemLength
, char *available
, int menuType
, int menuDefault
)
1043 int i
, ylast
= y
, key
= 0, current
= menuDefault
;
1044 if( !( menuType
& ( MENU_HORIZ
| MENU_VERT
) ) )
1046 print_warning("Menu without direction. Defaulting horizontal.");
1047 menuType
|= MENU_HORIZ
;
1049 /* Make sure that the current is one of the available items */
1050 while( !strchr(available
, menuItems
[current
].key
) )
1053 if( !menuItems
[current
].key
) current
= 0;
1055 /* Repeat until allowable choice has been made */
1058 /* Display the menu */
1059 ylast
= menuUpdate( y
, x
, menuItems
, itemLength
, available
,
1060 menuType
, current
);
1063 /* Clear out all prompts and such */
1065 for( i
= y
; i
< ylast
; i
++ )
1070 move( WARNING_START
+ 1, 0 );
1075 /* Check whether this is a real ESC or one of extended keys */
1076 /*nodelay(stdscr, TRUE);*/
1078 /*nodelay(stdscr, FALSE);*/
1079 if( key
== /*ERR*/ ESC
)
1081 /* This is a real ESC */
1086 /* This is one extended keys */
1089 case 'A': /* Up arrow */
1090 if( menuType
& MENU_VERT
)
1094 if( current
< 0 ) while( menuItems
[current
+1].key
) current
++ ;
1095 } while( !strchr( available
, menuItems
[current
].key
) );
1101 case 'B': /* Down arrow */
1102 if( menuType
& MENU_VERT
)
1106 if( !menuItems
[current
].key
) current
= 0 ;
1107 } while( !strchr( available
, menuItems
[current
].key
) );
1113 case 'C': /* Right arrow */
1114 if( menuType
& MENU_HORIZ
)
1118 if( !menuItems
[current
].key
)
1122 } while( !strchr( available
, menuItems
[current
].key
) );
1128 case 'D': /* Left arrow */
1129 if( menuType
& MENU_HORIZ
)
1135 while( menuItems
[current
+ 1].key
) current
++ ;
1137 } while( !strchr( available
, menuItems
[current
].key
) );
1146 /* Enter equals to the keyboard shortcut of current menu item */
1149 key
= menuItems
[current
].key
;
1151 /* Should all keys to be accepted? */
1152 if( key
&& (menuType
& MENU_ACCEPT_OTHERS
) ) break;
1153 /* Is pressed key among acceptable ones */
1154 if( key
&& (strchr(available
, tolower(key
)) || strchr(available
, key
)))
1156 /* The key has not been accepted so far -> let's reject it */
1161 print_warning("Illegal key");
1164 /* Clear out prompts and such */
1166 for( i
= y
; i
<= ylast
; i
++ )
1171 move( WARNING_START
+ 1, 0 );
1176 /* A function which displays "Press a key to continue" *
1177 * and waits for a keypress. *
1178 * Perhaps calling function menuSelect is a bit overkill but who cares? */
1180 void menuContinue(void)
1182 static struct MenuItem menuContinueBtn
[]=
1184 { 'c', "", "Press a key to continue" },
1188 menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1189 menuContinueBtn
, 0, "c", MENU_HORIZ
| MENU_ACCEPT_OTHERS
, 0 );
1192 /* Function menuSelect takes way too many parameters *
1193 * Luckily, most of time we can do with this function */
1195 int menuSimple(struct MenuItem
*menuItems
, int menuDefault
)
1197 int i
, j
, itemLength
= 0;
1198 char available
[MENU_MAX_ITEMS
];
1199 for(i
= 0; menuItems
[i
].key
; i
++)
1201 j
= strlen( menuItems
[i
].name
);
1202 if( j
> itemLength
) itemLength
= j
;
1203 available
[i
] = menuItems
[i
].key
;
1206 return menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuItems
, itemLength
,
1207 available
, MENU_HORIZ
| MENU_BUTTON
, menuDefault
);
1210 /* End of command menu support code */
1212 void new_part(int i
)
1214 char response
[LINE_LENGTH
], def
[LINE_LENGTH
];
1216 int first
= p_info
[i
].first_sector
;
1217 int last
= p_info
[i
].last_sector
;
1222 int num_sects
= last
- first
+ 1;
1225 if (p_info
[i
].num
== PRI_OR_LOG
) {
1226 static struct MenuItem menuPartType
[]=
1228 { 'p', "Primary", "Create a new primary partition" },
1229 { 'l', "Logical", "Create a new logical partition" },
1230 { ESC
, "Cancel", "Don't create a partition" },
1234 c
= menuSimple( menuPartType
, 0 );
1235 if (toupper(c
) == 'P')
1236 num
= find_primary();
1237 else if (toupper(c
) == 'L')
1238 num
= find_logical(i
);
1241 } else if (p_info
[i
].num
== PRIMARY
)
1242 num
= find_primary();
1243 else if (p_info
[i
].num
== LOGICAL
)
1244 num
= find_logical(i
);
1246 print_warning("!!! Internal error !!!");
1248 sprintf(def
, "%.2f", ceiling(num_sects
/20.48)/100);
1249 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
, "Size (in MB): ");
1250 if ((len
= get_string(response
, LINE_LENGTH
, def
)) <= 0 &&
1254 #define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads)))
1256 j
< len
-1 && (isdigit(response
[j
]) || response
[j
] == '.');
1258 if (toupper(response
[j
]) == 'K') {
1259 num_sects
= num_cyls(atof(response
)*1024)*sectors
*heads
;
1260 } else if (toupper(response
[j
]) == 'M') {
1261 num_sects
= num_cyls(atof(response
)*1024*1024)*sectors
*heads
;
1262 } else if (toupper(response
[j
]) == 'C') {
1263 num_sects
= round_int(atof(response
))*sectors
*heads
;
1264 } else if (toupper(response
[j
]) == 'S') {
1265 num_sects
= round_int(atof(response
));
1267 num_sects
= num_cyls(atof(response
)*1024*1024)*sectors
*heads
;
1271 if (num_sects
<= 0 ||
1272 num_sects
> p_info
[i
].last_sector
- p_info
[i
].first_sector
+ 1)
1275 move( COMMAND_LINE_Y
, COMMAND_LINE_X
); clrtoeol();
1276 if (num_sects
< p_info
[i
].last_sector
- p_info
[i
].first_sector
+ 1) {
1277 /* Determine where inside free space to put partition.
1279 static struct MenuItem menuPlace
[]=
1281 { 'b', "Beginning", "Add partition at beginning of free space" },
1282 { 'e', "End", "Add partition at end of free space" },
1283 { ESC
, "Cancel", "Don't create a partition" },
1286 c
= menuSimple( menuPlace
, 0 );
1287 if (toupper(c
) == 'B')
1288 last
= first
+ num_sects
- 1;
1289 else if (toupper(c
) == 'E')
1290 first
= last
- num_sects
+ 1;
1295 if (IS_LOGICAL(num
) && !is_extended(ext_info
.id
)) {
1296 /* We want to add a logical partition, but need to create an
1297 * extended partition first.
1299 if ((ext
= find_primary()) < 0) {
1300 print_warning(NEED_EXT
);
1303 (void) add_part(ext
, DOS_EXTENDED
, 0, first
, last
,
1304 (first
== 0 ? sectors
: 0), 0);
1305 first
= ext_info
.first_sector
+ ext_info
.offset
;
1308 if (IS_LOGICAL(num
))
1311 /* Now we have a complete partition to ourselves */
1312 if (first
== 0 || IS_LOGICAL(num
))
1315 (void) add_part(num
, id
, flags
, first
, last
, offset
, 0);
1318 void clear_p_info(void)
1321 p_info
[0].first_sector
= 0;
1322 p_info
[0].last_sector
= sectors
*heads
*cylinders
- 1;
1323 p_info
[0].offset
= 0;
1324 p_info
[0].flags
= 0;
1325 p_info
[0].id
= FREE_SPACE
;
1326 p_info
[0].num
= PRI_OR_LOG
;
1328 ext_info
.first_sector
= 0;
1329 ext_info
.last_sector
= 0;
1330 ext_info
.offset
= 0;
1332 ext_info
.id
= FREE_SPACE
;
1333 ext_info
.num
= PRIMARY
;
1336 void fill_p_info(void)
1339 struct partition
*p
;
1340 struct hd_geometry geometry
;
1341 partition_table buffer
;
1342 partition_info tmp_ext
= { 0, 0, 0, 0, FREE_SPACE
, PRIMARY
};
1344 if ((fd
= open(disk_device
, O_RDWR
)) < 0) {
1345 if ((fd
= open(disk_device
, O_RDONLY
)) < 0)
1347 opentype
= O_RDONLY
;
1348 print_warning(READONLY_WARN
);
1349 if (curses_started
) {
1358 /* Blocks are visible in more than one way:
1359 e.g. as block on /dev/hda and as block on /dev/hda3
1360 By a bug in the Linux buffer cache, we will see the old
1361 contents of /dev/hda when the change was made to /dev/hda3.
1362 In order to avoid this, discard all blocks on /dev/hda.
1363 Note that partition table blocks do not live in /dev/hdaN,
1364 so this only plays a role if we want to show volume labels. */
1365 ioctl(fd
, BLKFLSBUF
); /* ignore errors */
1366 /* e.g. Permission Denied */
1368 if (!ioctl(fd
, HDIO_GETGEO
, &geometry
)) {
1370 heads
= geometry
.heads
;
1372 sectors
= geometry
.sectors
;
1374 cylinders
= geometry
.cylinders
;
1377 if (!heads
|| !sectors
|| !cylinders
)
1378 fatal(BAD_GEOMETRY
, 3); /* probably a file or cdrom */
1380 read_sector(buffer
.c
.b
, 0);
1385 for (i
= 0; i
< 4; i
++) {
1386 p
= & buffer
.p
.part
[i
];
1387 bs
= get_start_sect(p
);
1388 bsz
= get_nr_sects(p
);
1390 if (p
->sys_ind
> 0 &&
1391 add_part(i
, p
->sys_ind
, p
->boot_ind
,
1392 ((bs
<= sectors
) ? 0 : bs
),
1394 ((bs
<= sectors
) ? bs
: 0),
1396 fatal(BAD_PRIMARY
, 4);
1398 if (is_extended(buffer
.p
.part
[i
].sys_ind
))
1402 if (is_extended(tmp_ext
.id
)) {
1404 logical_sectors
[logical
] =
1405 ext_info
.first_sector
+ ext_info
.offset
;
1406 read_sector(buffer
.c
.b
, logical_sectors
[logical
++]);
1410 pn
< 4 && (!buffer
.p
.part
[pn
].sys_ind
||
1411 is_extended(buffer
.p
.part
[pn
].sys_ind
));
1415 p
= & buffer
.p
.part
[pn
];
1416 bs
= get_start_sect(p
);
1417 bsz
= get_nr_sects(p
);
1419 if (add_part(i
++, p
->sys_ind
, p
->boot_ind
,
1420 logical_sectors
[logical
-1],
1421 logical_sectors
[logical
-1] + bs
+ bsz
- 1,
1423 fatal(BAD_LOGICAL
, 4);
1427 pn
< 4 && !is_extended(buffer
.p
.part
[pn
].sys_ind
);
1430 p
= & buffer
.p
.part
[pn
];
1431 bs
= get_start_sect(p
);
1432 logical_sectors
[logical
] = ext_info
.first_sector
1433 + ext_info
.offset
+ bs
;
1434 read_sector(buffer
.c
.b
, logical_sectors
[logical
++]);
1436 } while (pn
< 4 && logical
< MAXIMUM_PARTS
-4);
1441 void fill_part_table(struct partition
*p
, partition_info
*pi
)
1445 p
->boot_ind
= pi
->flags
;
1446 p
->sys_ind
= pi
->id
;
1447 if (IS_LOGICAL(pi
->num
))
1448 set_start_sect(p
,pi
->offset
);
1450 set_start_sect(p
,pi
->first_sector
+ pi
->offset
);
1451 set_nr_sects(p
, pi
->last_sector
- (pi
->first_sector
+pi
->offset
) + 1);
1452 sects
= (((pi
->first_sector
+pi
->offset
)/(sectors
*heads
) > 1023) ?
1453 heads
*sectors
*1024 - 1 : pi
->first_sector
+pi
->offset
);
1454 set_hsc(p
->head
, p
->sector
, p
->cyl
, sects
);
1455 sects
= ((pi
->last_sector
/(sectors
*heads
) > 1023) ?
1456 heads
*sectors
*1024 - 1 : pi
->last_sector
);
1457 set_hsc(p
->end_head
, p
->end_sector
, p
->end_cyl
, sects
);
1460 void fill_primary_table(partition_table
*buffer
)
1464 /* Zero out existing table */
1465 for (i
= 0x1BE; i
< SECTOR_SIZE
; i
++)
1468 for (i
= 0; i
< num_parts
; i
++)
1469 if (IS_PRIMARY(p_info
[i
].num
))
1470 fill_part_table(&(buffer
->p
.part
[p_info
[i
].num
]), &(p_info
[i
]));
1472 if (is_extended(ext_info
.id
))
1473 fill_part_table(&(buffer
->p
.part
[ext_info
.num
]), &ext_info
);
1475 buffer
->p
.magicflag
[0] = PART_TABLE_FLAG0
;
1476 buffer
->p
.magicflag
[1] = PART_TABLE_FLAG1
;
1479 void fill_logical_table(partition_table
*buffer
, partition_info
*pi
)
1481 struct partition
*p
;
1484 for (i
= 0; i
< logical
&& pi
->first_sector
!= logical_sectors
[i
]; i
++);
1485 if (i
== logical
|| buffer
->p
.magicflag
[0] != PART_TABLE_FLAG0
1486 || buffer
->p
.magicflag
[1] != PART_TABLE_FLAG1
)
1487 for (i
= 0; i
< SECTOR_SIZE
; i
++)
1490 /* Zero out existing table */
1491 for (i
= 0x1BE; i
< SECTOR_SIZE
; i
++)
1494 fill_part_table(&(buffer
->p
.part
[0]), pi
);
1497 i
< num_parts
&& pi
->num
!= p_info
[i
].num
- 1;
1500 if (i
< num_parts
) {
1501 p
= &(buffer
->p
.part
[1]);
1505 p
->sys_ind
= DOS_EXTENDED
;
1506 set_start_sect(p
, pi
->first_sector
- ext_info
.first_sector
- ext_info
.offset
);
1507 set_nr_sects(p
, pi
->last_sector
- pi
->first_sector
+ 1);
1508 sects
= ((pi
->first_sector
/(sectors
*heads
) > 1023) ?
1509 heads
*sectors
*1024 - 1 : pi
->first_sector
);
1510 set_hsc(p
->head
, p
->sector
, p
->cyl
, sects
);
1511 sects
= ((pi
->last_sector
/(sectors
*heads
) > 1023) ?
1512 heads
*sectors
*1024 - 1 : pi
->last_sector
);
1513 set_hsc(p
->end_head
, p
->end_sector
, p
->end_cyl
, sects
);
1516 buffer
->p
.magicflag
[0] = PART_TABLE_FLAG0
;
1517 buffer
->p
.magicflag
[1] = PART_TABLE_FLAG1
;
1520 void write_part_table(void)
1522 int i
, ct
, done
= FALSE
, len
;
1523 partition_table buffer
;
1526 char response
[LINE_LENGTH
];
1528 if (opentype
== O_RDONLY
) {
1529 print_warning(READONLY_WARN
);
1537 if(fstat(fd
, &s
) == 0 && S_ISBLK(s
.st_mode
))
1541 print_warning(WRITE_WARN
);
1544 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1545 "Are you sure you want write the partition table "
1546 "to disk? (yes or no): ");
1547 len
= get_string(response
, LINE_LENGTH
, NULL
);
1549 if (len
== GS_ESCAPE
)
1551 else if (len
== 2 &&
1552 toupper(response
[0]) == 'N' &&
1553 toupper(response
[1]) == 'O') {
1554 print_warning(NO_WRITE
);
1556 } else if (len
== 3 &&
1557 toupper(response
[0]) == 'Y' &&
1558 toupper(response
[1]) == 'E' &&
1559 toupper(response
[2]) == 'S')
1562 print_warning(YES_NO
);
1566 print_warning(WRITING_PART
);
1570 read_sector(buffer
.c
.b
, 0);
1571 fill_primary_table(&buffer
);
1572 write_sector(buffer
.c
.b
, 0);
1574 for (i
= 0; i
< num_parts
; i
++)
1575 if (IS_LOGICAL(p_info
[i
].num
)) {
1576 read_sector(buffer
.c
.b
, p_info
[i
].first_sector
);
1577 fill_logical_table(&buffer
, &(p_info
[i
]));
1578 write_sector(buffer
.c
.b
, p_info
[i
].first_sector
);
1584 if (!ioctl(fd
,BLKRRPART
))
1591 print_warning(YES_WRITE
);
1593 print_warning(RRPART_FAILED
);
1595 print_warning(YES_WRITE
);
1597 /* Check: unique bootable primary partition? */
1599 for (i
= 0; i
< num_parts
; i
++)
1600 if (IS_PRIMARY(i
) && p_info
[i
].flags
== ACTIVE_FLAG
)
1603 print_warning(NOT_DOS_MBR_BOOTABLE
);
1606 void fp_printf(FILE *fp
, char *format
, ...)
1612 va_start(args
, format
);
1613 vsprintf(buf
, format
, args
);
1617 /* The following works best if the string to be printed has at
1618 most only one newline. */
1620 getyx(stdscr
, y
, x
);
1621 if (y
>= COMMAND_LINE_Y
-2) {
1627 fprintf(fp
, "%s", buf
);
1630 #define MAX_PER_LINE 16
1631 void print_file_buffer(FILE *fp
, char *buffer
)
1635 for (i
= 0, l
= 0; i
< SECTOR_SIZE
; i
++, l
++) {
1637 fp_printf(fp
, "0x%03X:", i
);
1638 fp_printf(fp
, " %02X", (unsigned char) buffer
[i
]);
1639 if (l
== MAX_PER_LINE
- 1) {
1640 fp_printf(fp
, "\n");
1645 fp_printf(fp
, "\n");
1646 fp_printf(fp
, "\n");
1649 void print_raw_table(void)
1652 partition_table buffer
;
1653 char fname
[LINE_LENGTH
];
1660 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1661 "Enter filename or press RETURN to display on screen: ");
1663 if ((to_file
= get_string(fname
, LINE_LENGTH
, NULL
)) < 0)
1667 if ((fp
= fopen(fname
, "w")) == NULL
) {
1668 char errstr
[LINE_LENGTH
];
1669 sprintf(errstr
, PRINT_OPEN_ERR
, fname
);
1670 print_warning(errstr
);
1680 fp_printf(fp
, "Disk Drive: %s\n", disk_device
);
1682 fp_printf(fp
, "Sector 0:\n");
1683 read_sector(buffer
.c
.b
, 0);
1684 fill_primary_table(&buffer
);
1685 print_file_buffer(fp
, buffer
.c
.b
);
1687 for (i
= 0; i
< num_parts
; i
++)
1688 if (IS_LOGICAL(p_info
[i
].num
)) {
1689 fp_printf(fp
, "Sector %d:\n", p_info
[i
].first_sector
);
1690 read_sector(buffer
.c
.b
, p_info
[i
].first_sector
);
1691 fill_logical_table(&buffer
, &(p_info
[i
]));
1692 print_file_buffer(fp
, buffer
.c
.b
);
1703 void print_p_info_entry(FILE *fp
, partition_info
*p
)
1708 if (p
->id
== UNUSABLE
)
1709 fp_printf(fp
, " None ");
1710 else if (p
->id
== FREE_SPACE
&& p
->num
== PRI_OR_LOG
)
1711 fp_printf(fp
, " Pri/Log");
1712 else if (p
->id
== FREE_SPACE
&& p
->num
== PRIMARY
)
1713 fp_printf(fp
, " Primary");
1714 else if (p
->id
== FREE_SPACE
&& p
->num
== LOGICAL
)
1715 fp_printf(fp
, " Logical");
1717 fp_printf(fp
, "%2d %-7.7s", p
->num
+1,
1718 IS_LOGICAL(p
->num
) ? "Logical" : "Primary");
1722 fp_printf(fp
, "%8d%c", p
->first_sector
,
1723 ((p
->first_sector
/(sectors
*heads
)) !=
1724 ((float)p
->first_sector
/(sectors
*heads
)) ?
1727 fp_printf(fp
, "%8d%c", p
->last_sector
,
1728 (((p
->last_sector
+1)/(sectors
*heads
)) !=
1729 ((float)(p
->last_sector
+1)/(sectors
*heads
)) ?
1732 fp_printf(fp
, "%7d%c", p
->offset
,
1733 ((((p
->first_sector
== 0 || IS_LOGICAL(p
->num
)) &&
1734 (p
->offset
!= sectors
)) ||
1735 (p
->first_sector
!= 0 && IS_PRIMARY(p
->num
) &&
1739 size
= p
->last_sector
- p
->first_sector
+ 1;
1740 fp_printf(fp
, "%8d%c", size
,
1741 ((size
/(sectors
*heads
)) != ((float)size
/(sectors
*heads
)) ?
1746 if (p
->id
== UNUSABLE
)
1747 sprintf(part_str
, "%.17s", "Unusable");
1748 else if (p
->id
== FREE_SPACE
)
1749 sprintf(part_str
, "%.17s", "Free Space");
1750 else if (partition_type
[p
->id
])
1751 sprintf(part_str
, "%.17s (%02X)", partition_type
[p
->id
], p
->id
);
1753 sprintf(part_str
, "%.17s (%02X)", "Unknown", p
->id
);
1754 fp_printf(fp
, "%-22.22s", part_str
);
1758 if (p
->flags
== ACTIVE_FLAG
)
1759 fp_printf(fp
, "Boot (%02X)", p
->flags
);
1760 else if (p
->flags
!= 0)
1761 fp_printf(fp
, "Unknown (%02X)", p
->flags
);
1763 fp_printf(fp
, "None (%02X)", p
->flags
);
1765 fp_printf(fp
, "\n");
1768 void print_p_info(void)
1770 char fname
[LINE_LENGTH
];
1772 int i
, to_file
, pext
= is_extended(ext_info
.id
);
1778 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1779 "Enter filename or press RETURN to display on screen: ");
1781 if ((to_file
= get_string(fname
, LINE_LENGTH
, NULL
)) < 0)
1785 if ((fp
= fopen(fname
, "w")) == NULL
) {
1786 char errstr
[LINE_LENGTH
];
1787 sprintf(errstr
, PRINT_OPEN_ERR
, fname
);
1788 print_warning(errstr
);
1798 fp_printf(fp
, "Partition Table for %s\n", disk_device
);
1799 fp_printf(fp
, "\n");
1800 fp_printf(fp
, " First Last\n");
1801 fp_printf(fp
, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n");
1802 fp_printf(fp
, "-- ------- -------- --------- ------ --------- ---------------------- ---------\n");
1804 for (i
= 0; i
< num_parts
; i
++) {
1805 if (pext
&& (p_info
[i
].first_sector
>= ext_info
.first_sector
)) {
1806 print_p_info_entry(fp
,&ext_info
);
1809 print_p_info_entry(fp
, &(p_info
[i
]));
1820 void print_part_entry(FILE *fp
, int num
, partition_info
*pi
)
1822 int first
= 0, start
= 0, end
= 0, size
= 0;
1823 int ss
= 0, sh
= 0, sc
= 0;
1824 int es
= 0, eh
= 0, ec
= 0;
1825 int flags
= 0, id
= 0;
1831 if (IS_LOGICAL(num
))
1834 first
= pi
->first_sector
+ pi
->offset
;
1836 start
= pi
->first_sector
+ pi
->offset
;
1837 end
= pi
->last_sector
;
1838 size
= end
- start
+ 1;
1839 if ((start
/(sectors
*heads
)) > 1023)
1840 start
= heads
*sectors
*1024 - 1;
1841 if ((end
/(sectors
*heads
)) > 1023)
1842 end
= heads
*sectors
*1024 - 1;
1844 ss
= start
% sectors
+ 1;
1849 es
= end
% sectors
+ 1;
1855 fp_printf(fp
, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %8d %9d\n",
1856 num
+1, flags
, sh
, ss
, sc
, id
, eh
, es
, ec
, first
, size
);
1860 void print_part_table(void)
1863 char fname
[LINE_LENGTH
];
1870 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
1871 "Enter filename or press RETURN to display on screen: ");
1873 if ((to_file
= get_string(fname
, LINE_LENGTH
, NULL
)) < 0)
1877 if ((fp
= fopen(fname
, "w")) == NULL
) {
1878 char errstr
[LINE_LENGTH
];
1879 sprintf(errstr
, PRINT_OPEN_ERR
, fname
);
1880 print_warning(errstr
);
1890 fp_printf(fp
, "Partition Table for %s\n", disk_device
);
1891 fp_printf(fp
, "\n");
1892 fp_printf(fp
, " ---Starting--- ----Ending---- Start Number of\n");
1893 fp_printf(fp
, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n");
1894 fp_printf(fp
, "-- ----- ---- ---- ---- ---- ---- ---- ---- -------- ---------\n");
1896 for (i
= 0; i
< 4; i
++) {
1898 j
< num_parts
&& (p_info
[j
].id
<= 0 || p_info
[j
].num
!= i
);
1900 if (j
< num_parts
) {
1901 print_part_entry(fp
, i
, &(p_info
[j
]));
1902 } else if (is_extended(ext_info
.id
) && ext_info
.num
== i
) {
1903 print_part_entry(fp
, i
, &ext_info
);
1905 print_part_entry(fp
, i
, NULL
);
1909 for (i
= 0; i
< num_parts
; i
++)
1910 if (IS_LOGICAL(p_info
[i
].num
))
1911 print_part_entry(fp
, p_info
[i
].num
, &(p_info
[i
]));
1921 void print_tables(void)
1925 static struct MenuItem menuFormat
[]=
1927 { 'r', "Raw", "Print the table using raw data format" },
1928 { 's', "Sectors", "Print the table ordered by sectors" },
1929 { 't', "Table", "Just print the partition table" },
1930 { ESC
, "Cancel", "Don't print the table" },
1935 switch ( toupper(menuSimple( menuFormat
, 2)) ) {
1954 #define END_OF_HELP "EOHS!"
1955 #define NEW_HELP_SCREEN "SNHS!"
1958 char *help_text
[] = {
1959 "Help Screen for cfdisk " VERSION
,
1961 "This is cfdisk, a curses based disk partitioning programs, which",
1962 "allows you to create, delete and modify partitions on your hard",
1965 "Copyright (C) 1994-1998 Kevin E. Martin & aeb",
1969 " b Toggle bootable flag of the current partition",
1970 " d Delete the current partition",
1971 " g Change cylinders, heads, sectors-per-track parameters",
1972 " WARNING: This option should only be used by people who",
1973 " know what they are doing.",
1974 " h Print this screen",
1975 " m Maximize disk usage of the current partition",
1976 " Note: This may make the partition incompatible with",
1978 " n Create new partition from free space",
1979 " p Print partition table to the screen or to a file",
1980 " There are several different formats for the partition",
1981 " that you can choose from:",
1982 " r - Raw data (exactly what would be written to disk)",
1983 " s - Table ordered by sectors",
1984 " t - Table in raw format",
1985 " q Quit program without writing partition table",
1986 " t Change the filesystem type",
1987 " u Change units of the partition size display",
1988 " Rotates through Mb, sectors and cylinders",
1989 " W Write partition table to disk (must enter upper case W)",
1990 " Since this might destroy data on the disk, you must",
1991 " either confirm or deny the write by entering `yes' or",
1993 "Up Arrow Move cursor to the previous partition",
1994 "Down Arrow Move cursor to the next partition",
1995 "CTRL-L Redraws the screen",
1996 " ? Print this screen",
1998 "Note: All of the commands can be entered with either upper or lower",
1999 "case letters (except for Writes).",
2008 while (strcmp(help_text
[cur_line
], END_OF_HELP
))
2009 if (!strcmp(help_text
[cur_line
], NEW_HELP_SCREEN
)) {
2015 fp_printf(fp
, "%s\n", help_text
[cur_line
++]);
2020 int change_geometry(void)
2022 int ret_val
= FALSE
;
2024 char def
[LINE_LENGTH
];
2025 char response
[LINE_LENGTH
];
2029 static struct MenuItem menuGeometry
[]=
2031 { 'c', "Cylinders", "Change cylinder geometry" },
2032 { 'h', "Heads", "Change head geometry" },
2033 { 's', "Sectors", "Change sector geometry" },
2034 { 'd', "Done", "Done with changing geometry" },
2037 move(COMMAND_LINE_Y
, COMMAND_LINE_X
);
2043 switch (toupper( menuSimple(menuGeometry
, 3) )) {
2045 sprintf(def
, "%d", cylinders
);
2046 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2047 "Enter the number of cylinders: ");
2048 if (get_string(response
, LINE_LENGTH
, def
) > 0) {
2049 tmp_val
= atoi(response
);
2050 if (tmp_val
> 0 && tmp_val
<= MAX_CYLINDERS
) {
2051 cylinders
= tmp_val
;
2054 print_warning(BAD_CYLINDERS
);
2058 sprintf(def
, "%d", heads
);
2059 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2060 "Enter the number of heads: ");
2061 if (get_string(response
, LINE_LENGTH
, def
) > 0) {
2062 tmp_val
= atoi(response
);
2063 if (tmp_val
> 0 && tmp_val
<= MAX_HEADS
) {
2067 print_warning(BAD_HEADS
);
2071 sprintf(def
, "%d", sectors
);
2072 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
,
2073 "Enter the number of sectors per track: ");
2074 if (get_string(response
, LINE_LENGTH
, def
) > 0) {
2075 tmp_val
= atoi(response
);
2076 if (tmp_val
> 0 && tmp_val
<= MAX_SECTORS
) {
2080 print_warning(BAD_SECTORS
);
2094 int disk_end
= heads
*sectors
*cylinders
-1;
2096 if (p_info
[num_parts
-1].last_sector
> disk_end
) {
2097 while (p_info
[num_parts
-1].first_sector
> disk_end
) {
2098 if (p_info
[num_parts
-1].id
== FREE_SPACE
||
2099 p_info
[num_parts
-1].id
== UNUSABLE
)
2100 remove_part(num_parts
-1);
2102 del_part(num_parts
-1);
2105 p_info
[num_parts
-1].last_sector
= disk_end
;
2107 if (ext_info
.last_sector
> disk_end
)
2108 ext_info
.last_sector
= disk_end
;
2109 } else if (p_info
[num_parts
-1].last_sector
< disk_end
) {
2110 if (p_info
[num_parts
-1].id
== FREE_SPACE
||
2111 p_info
[num_parts
-1].id
== UNUSABLE
) {
2112 p_info
[num_parts
-1].last_sector
= disk_end
;
2114 insert_empty_part(num_parts
,
2115 p_info
[num_parts
-1].last_sector
+1,
2120 /* Make sure the partitions are correct */
2127 void change_id(int i
)
2129 char id
[LINE_LENGTH
], def
[LINE_LENGTH
];
2131 int num_across
, num_down
;
2132 int len
, new_id
= ((p_info
[i
].id
== LINUX
) ? LINUX_SWAP
: LINUX
);
2136 for (num_types
= 0, j
= 1; j
< NUM_PART_TYPES
; j
++)
2137 if (partition_type
[j
])
2140 num_across
= COLS
/COL_ID_WIDTH
;
2141 num_down
= (((float)num_types
)/num_across
+ 1);
2142 y_start
= COMMAND_LINE_Y
- 1 - num_down
;
2143 if (y_start
> DISK_TABLE_START
+cur_part
+4)
2144 y_start
= DISK_TABLE_START
+cur_part
+4;
2145 y_end
= y_start
+ num_down
- 1;
2147 for (j
= y_start
- 1; j
<= y_end
+ 1; j
++) {
2152 for (pos
= 0, j
= 1; j
< NUM_PART_TYPES
; j
++)
2153 if (partition_type
[j
]) {
2154 move(y_start
+ pos
% num_down
, (pos
/num_down
)*COL_ID_WIDTH
+ 1);
2155 printw("%02X %-16.16s", j
, partition_type
[j
]);
2159 sprintf(def
, "%02X", new_id
);
2160 mvaddstr(COMMAND_LINE_Y
, COMMAND_LINE_X
, "Enter filesystem type: ");
2161 if ((len
= get_string(id
, 2, def
)) <= 0 && len
!= GS_DEFAULT
)
2164 if (len
!= GS_DEFAULT
) {
2165 if (!isxdigit(id
[0]))
2167 new_id
= (isdigit(id
[0]) ? id
[0] - '0' : tolower(id
[0]) - 'a' + 10);
2169 if (isxdigit(id
[1]))
2170 new_id
= new_id
*16 +
2171 (isdigit(id
[1]) ? id
[1] - '0' : tolower(id
[1]) - 'a' + 10);
2178 print_warning(ID_EMPTY
);
2179 else if (is_extended(new_id
))
2180 print_warning(ID_EXT
);
2182 p_info
[i
].id
= new_id
;
2185 void draw_partition(int i
)
2188 int y
= i
+ DISK_TABLE_START
+ 2 - (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
;
2191 if (!arrow_cursor
) {
2193 for (j
= 0; j
< COLS
; j
++)
2197 if (p_info
[i
].id
> 0) {
2198 mvprintw(y
, NAME_START
,
2199 "%s%d", my_basename(disk_device
), p_info
[i
].num
+1);
2200 if (p_info
[i
].flags
) {
2201 if (p_info
[i
].flags
== ACTIVE_FLAG
)
2202 mvaddstr(y
, FLAGS_START
, "Boot");
2204 mvprintw(y
, FLAGS_START
, "Unk(%02X)", p_info
[i
].flags
);
2205 if (p_info
[i
].first_sector
== 0 || IS_LOGICAL(p_info
[i
].num
)) {
2206 if (p_info
[i
].offset
!= sectors
)
2209 if (p_info
[i
].offset
!= 0)
2213 if (p_info
[i
].first_sector
== 0 || IS_LOGICAL(p_info
[i
].num
)) {
2214 if (p_info
[i
].offset
!= sectors
)
2215 mvaddstr(y
, FLAGS_START
, "NC");
2217 if (p_info
[i
].offset
!= 0)
2218 mvaddstr(y
, FLAGS_START
, "NC");
2222 mvaddstr(y
, PTYPE_START
,
2223 (p_info
[i
].id
== UNUSABLE
? "" :
2224 (IS_LOGICAL(p_info
[i
].num
) ? "Logical" :
2225 (p_info
[i
].num
>= 0 ? "Primary" :
2226 (p_info
[i
].num
== PRI_OR_LOG
? "Pri/Log" :
2227 (p_info
[i
].num
== PRIMARY
? "Primary" : "Logical"))))));
2229 t
= partition_type_text(i
);
2231 mvaddstr(y
, FSTYPE_START
, t
);
2233 mvprintw(y
, FSTYPE_START
, "Unknown (%02X)", p_info
[i
].id
);
2235 if (p_info
[i
].volume_label
[0]) {
2236 int l
= strlen(p_info
[i
].volume_label
);
2237 int s
= SIZE_START
-5-l
;
2238 mvprintw(y
, (s
> LABEL_START
) ? LABEL_START
: s
,
2239 " [%s] ", p_info
[i
].volume_label
);
2242 size
= p_info
[i
].last_sector
- p_info
[i
].first_sector
+ 1;
2243 if (display_units
== SECTORS
)
2244 mvprintw(y
, SIZE_START
, "%9d", size
);
2245 else if (display_units
== CYLINDERS
)
2246 mvprintw(y
, SIZE_START
, "%9d", size
/(sectors
*heads
));
2248 mvprintw(y
, SIZE_START
, "%9.2f", ceiling(size
/20.48)/100);
2249 if (((size
/(sectors
*heads
)) != ceiling(size
/(sectors
*(float)heads
))) ||
2250 ((p_info
[i
].first_sector
/(sectors
*heads
)) !=
2251 ceiling(p_info
[i
].first_sector
/(sectors
*heads
))))
2252 mvprintw(y
, COLUMNS
-1, "*");
2255 void init_const(void)
2258 NAME_START
= (((float)NAME_START
)/COLUMNS
)*COLS
;
2259 FLAGS_START
= (((float)FLAGS_START
)/COLUMNS
)*COLS
;
2260 PTYPE_START
= (((float)PTYPE_START
)/COLUMNS
)*COLS
;
2261 FSTYPE_START
= (((float)FSTYPE_START
)/COLUMNS
)*COLS
;
2262 LABEL_START
= (((float)LABEL_START
)/COLUMNS
)*COLS
;
2263 SIZE_START
= (((float)SIZE_START
)/COLUMNS
)*COLS
;
2264 COMMAND_LINE_X
= (((float)COMMAND_LINE_X
)/COLUMNS
)*COLS
;
2266 COMMAND_LINE_Y
= LINES
- 4;
2267 WARNING_START
= LINES
- 2;
2269 if ((NUM_ON_SCREEN
= COMMAND_LINE_Y
- DISK_TABLE_START
- 3) <= 0)
2277 void draw_screen(void)
2282 line
= (char *)malloc((COLS
+1)*sizeof(char));
2284 if (warning_last_time
) {
2285 for (i
= 0; i
< COLS
; i
++) {
2286 move(WARNING_START
, i
);
2294 if (warning_last_time
)
2295 mvaddstr(WARNING_START
, 0, line
);
2298 sprintf(line
, "cfdisk %s", VERSION
);
2299 mvaddstr(HEADER_START
, (COLS
-strlen(line
))/2, line
);
2300 sprintf(line
, "Disk Drive: %s", disk_device
);
2301 mvaddstr(HEADER_START
+2, (COLS
-strlen(line
))/2, line
);
2302 sprintf(line
, "Heads: %d Sectors per Track: %d Cylinders: %d",
2303 heads
, sectors
, cylinders
);
2304 mvaddstr(HEADER_START
+3, (COLS
-strlen(line
))/2, line
);
2306 mvaddstr(DISK_TABLE_START
, NAME_START
, "Name");
2307 mvaddstr(DISK_TABLE_START
, FLAGS_START
, "Flags");
2308 mvaddstr(DISK_TABLE_START
, PTYPE_START
-1, "Part Type");
2309 mvaddstr(DISK_TABLE_START
, FSTYPE_START
, "FS Type");
2310 mvaddstr(DISK_TABLE_START
, LABEL_START
+1, "[Label]");
2311 if (display_units
== SECTORS
)
2312 mvaddstr(DISK_TABLE_START
, SIZE_START
, " Sectors");
2313 else if (display_units
== CYLINDERS
)
2314 mvaddstr(DISK_TABLE_START
, SIZE_START
, "Cylinders");
2316 mvaddstr(DISK_TABLE_START
, SIZE_START
, "Size (MB)");
2318 move(DISK_TABLE_START
+1, 1);
2319 for (i
= 1; i
< COLS
-1; i
++)
2322 if (NUM_ON_SCREEN
>= num_parts
)
2323 for (i
= 0; i
< num_parts
; i
++)
2326 for (i
= (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
;
2327 i
< NUM_ON_SCREEN
+ (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
&&
2335 int draw_cursor(int move
)
2337 if (move
!= 0 && (cur_part
+ move
< 0 || cur_part
+ move
>= num_parts
))
2341 mvaddstr(DISK_TABLE_START
+ cur_part
+ 2
2342 - (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
, 0, " ");
2344 draw_partition(cur_part
);
2348 if (((cur_part
- move
)/NUM_ON_SCREEN
)*NUM_ON_SCREEN
!=
2349 (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
)
2353 mvaddstr(DISK_TABLE_START
+ cur_part
+ 2
2354 - (cur_part
/NUM_ON_SCREEN
)*NUM_ON_SCREEN
, 0, "-->");
2357 draw_partition(cur_part
);
2364 void do_curses_fdisk(void)
2369 static struct MenuItem menuMain
[]=
2371 { 'b', "Bootable", "Toggle bootable flag of the current partition" },
2372 { 'd', "Delete", "Delete the current partition" },
2373 { 'g', "Geometry", "Change disk geometry (experts only)" },
2374 { 'h', "Help", "Print help screen" },
2375 { 'm', "Maximize", "Maximize disk usage of the current partition (experts only)" },
2376 { 'n', "New", "Create new partition from free space" },
2377 { 'p', "Print", "Print partition table to the screen or to a file" },
2378 { 'q', "Quit", "Quit program without writing partition table" },
2379 { 't', "Type", "Change the filesystem type (DOS, Linux, OS/2 and so on)" },
2380 { 'u', "Units", "Change units of the partition size display (MB, sect, cyl)" },
2381 { 'W', "Write", "Write partition table to disk (this might destroy data)" },
2388 old_SIGINT
= signal(SIGINT
, die
);
2389 old_SIGTERM
= signal(SIGTERM
, die
);
2391 signal(SIGINT
, old_SIGINT
);
2392 signal(SIGTERM
, old_SIGTERM
);
2406 (void)draw_cursor(0);
2408 if (p_info
[cur_part
].id
== FREE_SPACE
) {
2409 s
= ((opentype
== O_RDWR
) ? "hnpquW" : "hnpqu");
2410 command
= menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuMain
, 8,
2411 s
, MENU_HORIZ
| MENU_BUTTON
| MENU_ACCEPT_OTHERS
, 0);
2412 } else if (p_info
[cur_part
].id
> 0) {
2413 s
= ((opentype
== O_RDWR
) ? "bdhmpqtuW" : "bdhmpqtu");
2414 command
= menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuMain
, 8,
2415 s
, MENU_HORIZ
| MENU_BUTTON
| MENU_ACCEPT_OTHERS
, 0);
2417 s
= ((opentype
== O_RDWR
) ? "hpquW" : "hpqu");
2418 command
= menuSelect(COMMAND_LINE_Y
, COMMAND_LINE_X
, menuMain
, 8,
2419 s
, MENU_HORIZ
| MENU_BUTTON
| MENU_ACCEPT_OTHERS
, 0);
2421 switch ( command
) {
2424 if (p_info
[cur_part
].id
> 0)
2425 p_info
[cur_part
].flags
^= 0x80;
2427 print_warning(NO_FLAGS
);
2431 if (p_info
[cur_part
].id
> 0) {
2433 if (cur_part
>= num_parts
)
2434 cur_part
= num_parts
- 1;
2437 print_warning(DEL_EMPTY
);
2441 if (change_geometry())
2446 if (p_info
[cur_part
].id
> 0) {
2447 if (p_info
[cur_part
].first_sector
== 0 ||
2448 IS_LOGICAL(p_info
[cur_part
].num
)) {
2449 if (p_info
[cur_part
].offset
== sectors
)
2450 p_info
[cur_part
].offset
= 1;
2452 p_info
[cur_part
].offset
= sectors
;
2454 } else if (p_info
[cur_part
].offset
!= 0)
2455 p_info
[cur_part
].offset
= 0;
2457 print_warning(MAX_UNMAXABLE
);
2459 print_warning(MAX_UNMAXABLE
);
2463 if (p_info
[cur_part
].id
== FREE_SPACE
) {
2466 } else if (p_info
[cur_part
].id
== UNUSABLE
)
2467 print_warning(ADD_UNUSABLE
);
2469 print_warning(ADD_EXISTS
);
2482 if (p_info
[cur_part
].id
> 0) {
2483 change_id(cur_part
);
2486 print_warning(TYPE_EMPTY
);
2490 if (display_units
== MEGABYTES
)
2491 display_units
= SECTORS
;
2492 else if (display_units
== SECTORS
)
2493 display_units
= CYLINDERS
;
2494 else if (display_units
== CYLINDERS
)
2495 display_units
= MEGABYTES
;
2507 case MENU_UP
: /* Up arrow */
2508 if (!draw_cursor(-1))
2511 print_warning(NO_MORE_PARTS
);
2513 case MENU_DOWN
: /* Down arrow */
2514 if (!draw_cursor(1))
2517 print_warning(NO_MORE_PARTS
);
2524 print_warning(BAD_COMMAND
);
2525 putchar(BELL
); /* CTRL-G */
2532 void copyright(void)
2534 fprintf(stderr
, "Copyright (C) 1994-1997 Kevin E. Martin & aeb\n");
2537 void usage(char *prog_name
)
2539 fprintf(stderr
, "\nUsage:\n");
2540 fprintf(stderr
, "Print version:\n");
2541 fprintf(stderr
, "\t%s -v\n", prog_name
);
2542 fprintf(stderr
, "Print partition table:\n");
2543 fprintf(stderr
, "\t%s -P {r|s|t} [options] device\n", prog_name
);
2544 fprintf(stderr
, "Interactive use:\n");
2545 fprintf(stderr
, "\t%s [options] device\n", prog_name
);
2548 -a: Use arrow instead of highlighting;
2549 -z: Start with a zero partition table, instead of reading the pt from disk;
2550 -c C -h H -s S: Override the kernel's idea of the number of cylinders,
2551 the number of heads and the number of sectors/track.\n\n");
2557 main(int argc
, char **argv
)
2562 setlocale(LC_CTYPE
, "");
2564 while ((c
= getopt(argc
, argv
, "ac:h:s:vzP:")) != EOF
)
2567 arrow_cursor
= TRUE
;
2570 cylinders
= atoi(optarg
);
2571 if (cylinders
<= 0 || cylinders
> MAX_CYLINDERS
) {
2572 fprintf(stderr
, "%s: %s\n", argv
[0], BAD_CYLINDERS
);
2577 heads
= atoi(optarg
);
2578 if (heads
<= 0 || heads
> MAX_HEADS
) {
2579 fprintf(stderr
, "%s: %s\n", argv
[0], BAD_HEADS
);
2584 sectors
= atoi(optarg
);
2585 if (sectors
<= 0 || sectors
> MAX_SECTORS
) {
2586 fprintf(stderr
, "%s: %s\n", argv
[0], BAD_SECTORS
);
2591 fprintf(stderr
, "cfdisk %s\n", VERSION
);
2598 len
= strlen(optarg
);
2599 for (i
= 0; i
< len
; i
++) {
2600 switch (optarg
[i
]) {
2602 print_only
|= PRINT_RAW_TABLE
;
2605 print_only
|= PRINT_SECTOR_TABLE
;
2608 print_only
|= PRINT_PARTITION_TABLE
;
2621 if (argc
-optind
== 1)
2622 disk_device
= argv
[optind
];
2623 else if (argc
-optind
!= 0) {
2626 } else if ((fd
= open(DEFAULT_DEVICE
, O_RDONLY
)) < 0)
2627 disk_device
= ALTERNATE_DEVICE
;
2632 if (print_only
& PRINT_RAW_TABLE
)
2634 if (print_only
& PRINT_SECTOR_TABLE
)
2636 if (print_only
& PRINT_PARTITION_TABLE
)