1 /* vi: set sw=4 ts=4: */
2 /* fdisk.c -- Partition table manipulator for Linux.
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
10 #include <assert.h> /* assert */
13 /* Looks like someone forgot to add this to config system */
14 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
15 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
16 # define USE_FEATURE_FDISK_BLKSIZE(a)
19 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
21 #define DEFAULT_SECTOR_SIZE 512
22 #define MAX_SECTOR_SIZE 2048
23 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
24 #define MAXIMUM_PARTS 60
26 #define ACTIVE_FLAG 0x80
29 #define WIN98_EXTENDED 0x0f
30 #define LINUX_PARTITION 0x81
31 #define LINUX_SWAP 0x82
32 #define LINUX_NATIVE 0x83
33 #define LINUX_EXTENDED 0x85
34 #define LINUX_LVM 0x8e
35 #define LINUX_RAID 0xfd
39 unsigned char sectors;
40 unsigned short cylinders;
44 #define HDIO_GETGEO 0x0301 /* get device geometry */
46 static const char msg_building_new_label[] =
47 "Building a new %s. Changes will remain in memory only,\n"
48 "until you decide to write them. After that the previous content\n"
49 "won't be recoverable.\n\n";
51 static const char msg_part_already_defined[] =
52 "Partition %d is already defined, delete it before re-adding\n";
55 static unsigned sector_size = DEFAULT_SECTOR_SIZE;
56 static unsigned user_set_sector_size;
57 static unsigned sector_offset = 1;
59 #if ENABLE_FEATURE_OSF_LABEL
60 static int possibly_osf_label;
63 static unsigned heads, sectors, cylinders;
64 static void update_units(void);
68 unsigned char boot_ind; /* 0x80 - active */
69 unsigned char head; /* starting head */
70 unsigned char sector; /* starting sector */
71 unsigned char cyl; /* starting cylinder */
72 unsigned char sys_ind; /* What partition type */
73 unsigned char end_head; /* end head */
74 unsigned char end_sector; /* end sector */
75 unsigned char end_cyl; /* end cylinder */
76 unsigned char start4[4]; /* starting sector counting from 0 */
77 unsigned char size4[4]; /* nr of sectors in partition */
81 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
86 label_dos, label_sun, label_sgi, label_aix, label_osf
89 #define LABEL_IS_DOS (label_dos == current_label_type)
91 #if ENABLE_FEATURE_SUN_LABEL
92 #define LABEL_IS_SUN (label_sun == current_label_type)
93 #define STATIC_SUN static
95 #define LABEL_IS_SUN 0
96 #define STATIC_SUN extern
99 #if ENABLE_FEATURE_SGI_LABEL
100 #define LABEL_IS_SGI (label_sgi == current_label_type)
101 #define STATIC_SGI static
103 #define LABEL_IS_SGI 0
104 #define STATIC_SGI extern
107 #if ENABLE_FEATURE_AIX_LABEL
108 #define LABEL_IS_AIX (label_aix == current_label_type)
109 #define STATIC_AIX static
111 #define LABEL_IS_AIX 0
112 #define STATIC_AIX extern
115 #if ENABLE_FEATURE_OSF_LABEL
116 #define LABEL_IS_OSF (label_osf == current_label_type)
117 #define STATIC_OSF static
119 #define LABEL_IS_OSF 0
120 #define STATIC_OSF extern
123 enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
125 static enum label_type current_label_type;
127 static const char *disk_device;
128 static int fd; /* the disk */
129 static int partitions = 4; /* maximum partition + 1 */
130 static int display_in_cyl_units = 1;
131 static unsigned units_per_sector = 1;
132 #if ENABLE_FEATURE_FDISK_WRITABLE
133 static void change_units(void);
134 static void reread_partition_table(int leave);
135 static void delete_partition(int i);
136 static int get_partition(int warn, int max);
137 static void list_types(const char *const *sys);
138 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
140 static const char *partition_type(unsigned char type);
141 static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
142 static void get_geometry(void);
143 static int get_boot(enum action what);
148 static unsigned get_start_sect(const struct partition *p);
149 static unsigned get_nr_sects(const struct partition *p);
152 * per partition table entry data
154 * The four primary partitions have the same sectorbuffer (MBRbuffer)
155 * and have NULL ext_pointer.
156 * Each logical partition table entry has two pointers, one for the
157 * partition and one link to the next one.
160 struct partition *part_table; /* points into sectorbuffer */
161 struct partition *ext_pointer; /* points into sectorbuffer */
162 off_t offset; /* disk sector number */
163 char *sectorbuffer; /* disk sector contents */
164 #if ENABLE_FEATURE_FDISK_WRITABLE
165 char changed; /* boolean */
169 /* DOS partition types */
171 static const char *const i386_sys_types[] = {
175 "\x05" "Extended", /* DOS 3.3+ extended partition */
176 "\x06" "FAT16", /* DOS 16-bit >=32M */
177 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
178 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
179 "\x0b" "Win95 FAT32",
180 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
181 "\x0e" "Win95 FAT16 (LBA)",
182 "\x0f" "Win95 Ext'd (LBA)",
183 "\x11" "Hidden FAT12",
184 "\x12" "Compaq diagnostics",
185 "\x14" "Hidden FAT16 <32M",
186 "\x16" "Hidden FAT16",
187 "\x17" "Hidden HPFS/NTFS",
188 "\x1b" "Hidden Win95 FAT32",
189 "\x1c" "Hidden W95 FAT32 (LBA)",
190 "\x1e" "Hidden W95 FAT16 (LBA)",
191 "\x3c" "Part.Magic recovery",
192 "\x41" "PPC PReP Boot",
194 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
195 "\x80" "Old Minix", /* Minix 1.4a and earlier */
196 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
197 "\x82" "Linux swap", /* also Solaris */
199 "\x84" "OS/2 hidden C: drive",
200 "\x85" "Linux extended",
201 "\x86" "NTFS volume set",
202 "\x87" "NTFS volume set",
204 "\x9f" "BSD/OS", /* BSDI */
205 "\xa0" "Thinkpad hibernation",
206 "\xa5" "FreeBSD", /* various BSD flavours */
210 "\xab" "Darwin boot",
213 "\xbe" "Solaris boot",
215 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
216 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
217 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
218 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
219 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
220 autodetect using persistent
222 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
225 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
226 "\x09" "AIX bootable", /* AIX data or Coherent */
228 "\x18" "AST SmartSleep",
231 "\x40" "Venix 80286",
233 "\x4e" "QNX4.x 2nd part",
234 "\x4f" "QNX4.x 3rd part",
236 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
237 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
238 "\x53" "OnTrack DM6 Aux3",
242 "\x5c" "Priam Edisk",
244 "\x64" "Novell Netware 286",
245 "\x65" "Novell Netware 386",
246 "\x70" "DiskSecure Multi-Boot",
249 "\x94" "Amoeba BBT", /* (bad block table) */
251 "\xbb" "Boot Wizard hidden",
252 "\xc1" "DRDOS/sec (FAT-12)",
253 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
254 "\xc6" "DRDOS/sec (FAT-16)",
256 "\xda" "Non-FS data",
257 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
258 Concurrent DOS or CTOS */
259 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
260 "\xdf" "BootIt", /* BootIt EMBRM */
261 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
262 extended partition */
263 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
264 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
265 partition < 1024 cyl. */
267 "\xf4" "SpeedStor", /* SpeedStor large partition */
268 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
269 "\xff" "BBT", /* Xenix Bad Block Table */
279 char line_buffer[80];
280 char partname_buffer[80];
282 /* Raw disk label. For DOS-type partition tables the MBR,
283 * with descriptions of the primary partitions. */
284 char MBRbuffer[MAX_SECTOR_SIZE];
285 /* Partition tables */
286 struct pte ptes[MAXIMUM_PARTS];
288 /* bb_common_bufsiz1 is too small for this on 64 bit CPUs */
289 #define G (*ptr_to_globals)
291 #define line_ptr (G.line_ptr)
292 #define listingbuf (G.listingbuf)
293 #define line_buffer (G.line_buffer)
294 #define partname_buffer (G.partname_buffer)
295 #define MBRbuffer (G.MBRbuffer)
296 #define ptes (G.ptes)
301 #define IS_EXTENDED(i) \
302 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
304 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
306 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
308 #define pt_offset(b, n) \
309 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
311 #define sector(s) ((s) & 0x3f)
313 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
315 #define hsc2sector(h,s,c) \
316 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
318 #define set_hsc(h,s,c,sector) \
320 s = sector % sectors + 1; \
322 h = sector % heads; \
325 s |= (sector >> 2) & 0xc0; \
328 /* read line; return 0 or first printable char */
330 read_line(const char *prompt)
334 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
336 exit(0); /* Ctrl-D or Ctrl-C */
338 if (line_buffer[sz-1] == '\n')
339 line_buffer[--sz] = '\0';
341 line_ptr = line_buffer;
342 while (*line_ptr && !isgraph(*line_ptr))
348 * return partition name - uses static storage
351 partname(const char *dev, int pno, int lth)
358 bufp = partname_buffer;
359 bufsiz = sizeof(partname_buffer);
364 if (isdigit(dev[w-1]))
367 /* devfs kludge - note: fdisk partition names are not supposed
368 to equal kernel names, so there is no reason to do this */
369 if (strcmp(dev + w - 4, "disc") == 0) {
377 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
378 lth-wp-2, w, dev, p, pno);
380 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
385 #if ENABLE_FEATURE_FDISK_WRITABLE
387 set_all_unchanged(void)
391 for (i = 0; i < MAXIMUM_PARTS; i++)
395 static ATTRIBUTE_ALWAYS_INLINE void
400 #endif /* FEATURE_FDISK_WRITABLE */
402 static ATTRIBUTE_ALWAYS_INLINE struct partition *
403 get_part_table(int i)
405 return ptes[i].part_table;
410 { /* n==1: use singular */
412 return display_in_cyl_units ? "cylinder" : "sector";
413 return display_in_cyl_units ? "cylinders" : "sectors";
417 valid_part_table_flag(const char *mbuffer)
419 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
422 #if ENABLE_FEATURE_FDISK_WRITABLE
423 static ATTRIBUTE_ALWAYS_INLINE void
424 write_part_table_flag(char *b)
431 read_nonempty(const char *mesg)
433 while (!read_line(mesg)) /* repeat */;
438 read_maybe_empty(const char *mesg)
440 if (!read_line(mesg)) {
441 line_ptr = line_buffer;
449 read_hex(const char *const *sys)
453 read_nonempty("Hex code (type L to list codes): ");
454 if (*line_ptr == 'l' || *line_ptr == 'L') {
458 v = bb_strtoul(line_ptr, NULL, 16);
460 /* Bad input also triggers this */
465 #endif /* FEATURE_FDISK_WRITABLE */
467 #include "fdisk_aix.c"
470 unsigned char info[128]; /* Informative text string */
471 unsigned char spare0[14];
473 unsigned char spare1;
475 unsigned char spare2;
478 unsigned char spare1[246]; /* Boot information etc. */
479 unsigned short rspeed; /* Disk rotational speed */
480 unsigned short pcylcount; /* Physical cylinder count */
481 unsigned short sparecyl; /* extra sects per cylinder */
482 unsigned char spare2[4]; /* More magic... */
483 unsigned short ilfact; /* Interleave factor */
484 unsigned short ncyl; /* Data cylinder count */
485 unsigned short nacyl; /* Alt. cylinder count */
486 unsigned short ntrks; /* Tracks per cylinder */
487 unsigned short nsect; /* Sectors per track */
488 unsigned char spare3[4]; /* Even more magic... */
489 struct sun_partinfo {
490 uint32_t start_cylinder;
491 uint32_t num_sectors;
493 unsigned short magic; /* Magic number */
494 unsigned short csum; /* Label xor'd checksum */
496 #define sunlabel ((sun_partition *)MBRbuffer)
497 STATIC_OSF void bsd_select(void);
498 STATIC_OSF void xbsd_print_disklabel(int);
499 #include "fdisk_osf.c"
501 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
503 fdisk_swap16(uint16_t x)
505 return (x << 8) | (x >> 8);
509 fdisk_swap32(uint32_t x)
512 ((x & 0xFF00) << 8) |
513 ((x & 0xFF0000) >> 8) |
518 STATIC_SGI const char *const sgi_sys_types[];
519 STATIC_SGI unsigned sgi_get_num_sectors(int i);
520 STATIC_SGI int sgi_get_sysid(int i);
521 STATIC_SGI void sgi_delete_partition(int i);
522 STATIC_SGI void sgi_change_sysid(int i, int sys);
523 STATIC_SGI void sgi_list_table(int xtra);
524 #if ENABLE_FEATURE_FDISK_ADVANCED
525 STATIC_SGI void sgi_set_xcyl(void);
527 STATIC_SGI int verify_sgi(int verbose);
528 STATIC_SGI void sgi_add_partition(int n, int sys);
529 STATIC_SGI void sgi_set_swappartition(int i);
530 STATIC_SGI const char *sgi_get_bootfile(void);
531 STATIC_SGI void sgi_set_bootfile(const char* aFile);
532 STATIC_SGI void create_sgiinfo(void);
533 STATIC_SGI void sgi_write_table(void);
534 STATIC_SGI void sgi_set_bootpartition(int i);
535 #include "fdisk_sgi.c"
537 STATIC_SUN const char *const sun_sys_types[];
538 STATIC_SUN void sun_delete_partition(int i);
539 STATIC_SUN void sun_change_sysid(int i, int sys);
540 STATIC_SUN void sun_list_table(int xtra);
541 STATIC_SUN void add_sun_partition(int n, int sys);
542 #if ENABLE_FEATURE_FDISK_ADVANCED
543 STATIC_SUN void sun_set_alt_cyl(void);
544 STATIC_SUN void sun_set_ncyl(int cyl);
545 STATIC_SUN void sun_set_xcyl(void);
546 STATIC_SUN void sun_set_ilfact(void);
547 STATIC_SUN void sun_set_rspeed(void);
548 STATIC_SUN void sun_set_pcylcount(void);
550 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
551 STATIC_SUN void verify_sun(void);
552 STATIC_SUN void sun_write_table(void);
553 #include "fdisk_sun.c"
555 #if ENABLE_FEATURE_FDISK_WRITABLE
556 /* start_sect and nr_sects are stored little endian on all machines */
557 /* moreover, they are not aligned correctly */
559 store4_little_endian(unsigned char *cp, unsigned val)
566 #endif /* FEATURE_FDISK_WRITABLE */
569 read4_little_endian(const unsigned char *cp)
571 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
574 #if ENABLE_FEATURE_FDISK_WRITABLE
576 set_start_sect(struct partition *p, unsigned start_sect)
578 store4_little_endian(p->start4, start_sect);
583 get_start_sect(const struct partition *p)
585 return read4_little_endian(p->start4);
588 #if ENABLE_FEATURE_FDISK_WRITABLE
590 set_nr_sects(struct partition *p, unsigned nr_sects)
592 store4_little_endian(p->size4, nr_sects);
597 get_nr_sects(const struct partition *p)
599 return read4_little_endian(p->size4);
602 /* normally O_RDWR, -l option gives O_RDONLY */
603 static int type_open = O_RDWR;
606 static int ext_index; /* the prime extended partition */
607 static int listing; /* no aborts for fdisk -l */
608 static int dos_compatible_flag = ~0;
609 #if ENABLE_FEATURE_FDISK_WRITABLE
610 static int dos_changed;
611 static int nowarn; /* no warnings for fdisk -l/-s */
616 static unsigned user_cylinders, user_heads, user_sectors;
617 static unsigned pt_heads, pt_sectors;
618 static unsigned kern_heads, kern_sectors;
620 static off_t extended_offset; /* offset of link pointers */
622 static unsigned long long total_number_of_sectors;
625 static void fdisk_fatal(enum failure why)
631 longjmp(listingbuf, 1);
636 message = "cannot open %s";
639 message = "cannot read from %s";
642 message = "cannot seek on %s";
644 case unable_to_write:
645 message = "cannot write to %s";
648 message = "BLKGETSIZE ioctl failed on %s";
651 message = "fatal error";
654 bb_error_msg_and_die(message, disk_device);
658 seek_sector(off_t secno)
660 off_t offset = secno * sector_size;
661 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
662 fdisk_fatal(unable_to_seek);
665 #if ENABLE_FEATURE_FDISK_WRITABLE
667 write_sector(off_t secno, char *buf)
670 if (write(fd, buf, sector_size) != sector_size)
671 fdisk_fatal(unable_to_write);
675 /* Allocate a buffer and read a partition table sector */
677 read_pte(struct pte *pe, off_t offset)
680 pe->sectorbuffer = xmalloc(sector_size);
682 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
683 fdisk_fatal(unable_to_read);
684 #if ENABLE_FEATURE_FDISK_WRITABLE
687 pe->part_table = pe->ext_pointer = NULL;
691 get_partition_start(const struct pte *pe)
693 return pe->offset + get_start_sect(pe->part_table);
696 #if ENABLE_FEATURE_FDISK_WRITABLE
698 * Avoid warning about DOS partitions when no DOS partition was changed.
699 * Here a heuristic "is probably dos partition".
700 * We might also do the opposite and warn in all cases except
701 * for "is probably nondos partition".
704 is_dos_partition(int t)
706 return (t == 1 || t == 4 || t == 6 ||
707 t == 0x0b || t == 0x0c || t == 0x0e ||
708 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
709 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
710 t == 0xc1 || t == 0xc4 || t == 0xc6);
716 puts("Command Action");
718 puts("a\ttoggle a read only flag"); /* sun */
719 puts("b\tedit bsd disklabel");
720 puts("c\ttoggle the mountable flag"); /* sun */
721 puts("d\tdelete a partition");
722 puts("l\tlist known partition types");
723 puts("n\tadd a new partition");
724 puts("o\tcreate a new empty DOS partition table");
725 puts("p\tprint the partition table");
726 puts("q\tquit without saving changes");
727 puts("s\tcreate a new empty Sun disklabel"); /* sun */
728 puts("t\tchange a partition's system id");
729 puts("u\tchange display/entry units");
730 puts("v\tverify the partition table");
731 puts("w\twrite table to disk and exit");
732 #if ENABLE_FEATURE_FDISK_ADVANCED
733 puts("x\textra functionality (experts only)");
735 } else if (LABEL_IS_SGI) {
736 puts("a\tselect bootable partition"); /* sgi flavour */
737 puts("b\tedit bootfile entry"); /* sgi */
738 puts("c\tselect sgi swap partition"); /* sgi flavour */
739 puts("d\tdelete a partition");
740 puts("l\tlist known partition types");
741 puts("n\tadd a new partition");
742 puts("o\tcreate a new empty DOS partition table");
743 puts("p\tprint the partition table");
744 puts("q\tquit without saving changes");
745 puts("s\tcreate a new empty Sun disklabel"); /* sun */
746 puts("t\tchange a partition's system id");
747 puts("u\tchange display/entry units");
748 puts("v\tverify the partition table");
749 puts("w\twrite table to disk and exit");
750 } else if (LABEL_IS_AIX) {
751 puts("o\tcreate a new empty DOS partition table");
752 puts("q\tquit without saving changes");
753 puts("s\tcreate a new empty Sun disklabel"); /* sun */
755 puts("a\ttoggle a bootable flag");
756 puts("b\tedit bsd disklabel");
757 puts("c\ttoggle the dos compatibility flag");
758 puts("d\tdelete a partition");
759 puts("l\tlist known partition types");
760 puts("n\tadd a new partition");
761 puts("o\tcreate a new empty DOS partition table");
762 puts("p\tprint the partition table");
763 puts("q\tquit without saving changes");
764 puts("s\tcreate a new empty Sun disklabel"); /* sun */
765 puts("t\tchange a partition's system id");
766 puts("u\tchange display/entry units");
767 puts("v\tverify the partition table");
768 puts("w\twrite table to disk and exit");
769 #if ENABLE_FEATURE_FDISK_ADVANCED
770 puts("x\textra functionality (experts only)");
774 #endif /* FEATURE_FDISK_WRITABLE */
777 #if ENABLE_FEATURE_FDISK_ADVANCED
781 puts("Command Action");
783 puts("a\tchange number of alternate cylinders"); /*sun*/
784 puts("c\tchange number of cylinders");
785 puts("d\tprint the raw data in the partition table");
786 puts("e\tchange number of extra sectors per cylinder");/*sun*/
787 puts("h\tchange number of heads");
788 puts("i\tchange interleave factor"); /*sun*/
789 puts("o\tchange rotation speed (rpm)"); /*sun*/
790 puts("p\tprint the partition table");
791 puts("q\tquit without saving changes");
792 puts("r\treturn to main menu");
793 puts("s\tchange number of sectors/track");
794 puts("v\tverify the partition table");
795 puts("w\twrite table to disk and exit");
796 puts("y\tchange number of physical cylinders"); /*sun*/
797 } else if (LABEL_IS_SGI) {
798 puts("b\tmove beginning of data in a partition"); /* !sun */
799 puts("c\tchange number of cylinders");
800 puts("d\tprint the raw data in the partition table");
801 puts("e\tlist extended partitions"); /* !sun */
802 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
803 puts("h\tchange number of heads");
804 puts("p\tprint the partition table");
805 puts("q\tquit without saving changes");
806 puts("r\treturn to main menu");
807 puts("s\tchange number of sectors/track");
808 puts("v\tverify the partition table");
809 puts("w\twrite table to disk and exit");
810 } else if (LABEL_IS_AIX) {
811 puts("b\tmove beginning of data in a partition"); /* !sun */
812 puts("c\tchange number of cylinders");
813 puts("d\tprint the raw data in the partition table");
814 puts("e\tlist extended partitions"); /* !sun */
815 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
816 puts("h\tchange number of heads");
817 puts("p\tprint the partition table");
818 puts("q\tquit without saving changes");
819 puts("r\treturn to main menu");
820 puts("s\tchange number of sectors/track");
821 puts("v\tverify the partition table");
822 puts("w\twrite table to disk and exit");
824 puts("b\tmove beginning of data in a partition"); /* !sun */
825 puts("c\tchange number of cylinders");
826 puts("d\tprint the raw data in the partition table");
827 puts("e\tlist extended partitions"); /* !sun */
828 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
829 #if ENABLE_FEATURE_SGI_LABEL
830 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
832 puts("h\tchange number of heads");
833 puts("p\tprint the partition table");
834 puts("q\tquit without saving changes");
835 puts("r\treturn to main menu");
836 puts("s\tchange number of sectors/track");
837 puts("v\tverify the partition table");
838 puts("w\twrite table to disk and exit");
841 #endif /* ADVANCED mode */
843 #if ENABLE_FEATURE_FDISK_WRITABLE
844 static const char *const *
848 LABEL_IS_SUN ? sun_sys_types :
849 LABEL_IS_SGI ? sgi_sys_types :
853 #define get_sys_types() i386_sys_types
854 #endif /* FEATURE_FDISK_WRITABLE */
857 partition_type(unsigned char type)
860 const char *const *types = get_sys_types();
862 for (i = 0; types[i]; i++)
863 if ((unsigned char)types[i][0] == type)
870 #if ENABLE_FEATURE_FDISK_WRITABLE
874 return LABEL_IS_SUN ? sunlabel->infos[i].id :
875 (LABEL_IS_SGI ? sgi_get_sysid(i) :
876 ptes[i].part_table->sys_ind);
880 list_types(const char *const *sys)
885 unsigned done, next, size;
888 for (size = 0; sys[size]; size++) /* */;
891 for (i = COLS-1; i >= 0; i--) {
892 done += (size + i - done) / (i + 1);
893 last[COLS-1 - i] = done;
898 printf("%c%2x %-22.22s", i ? ' ' : '\n',
899 (unsigned char)sys[next][0],
901 next = last[i++] + done;
902 if (i >= COLS || next >= last[i]) {
906 } while (done < last[0]);
909 #endif /* FEATURE_FDISK_WRITABLE */
912 is_cleared_partition(const struct partition *p)
914 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
915 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
916 get_start_sect(p) || get_nr_sects(p));
920 clear_partition(struct partition *p)
924 memset(p, 0, sizeof(struct partition));
927 #if ENABLE_FEATURE_FDISK_WRITABLE
929 set_partition(int i, int doext, off_t start, off_t stop, int sysid)
935 p = ptes[i].ext_pointer;
936 offset = extended_offset;
938 p = ptes[i].part_table;
939 offset = ptes[i].offset;
943 set_start_sect(p, start - offset);
944 set_nr_sects(p, stop - start + 1);
945 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
946 start = heads*sectors*1024 - 1;
947 set_hsc(p->head, p->sector, p->cyl, start);
948 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
949 stop = heads*sectors*1024 - 1;
950 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
958 if (heads && sectors && cylinders)
961 printf("Unknown value(s) for:");
967 printf(" cylinders");
969 #if ENABLE_FEATURE_FDISK_WRITABLE
970 " (settable in the extra functions menu)"
979 int cyl_units = heads * sectors;
981 if (display_in_cyl_units && cyl_units)
982 units_per_sector = cyl_units;
984 units_per_sector = 1; /* in sectors */
987 #if ENABLE_FEATURE_FDISK_WRITABLE
991 if (LABEL_IS_DOS && cylinders > 1024 && !nowarn)
993 "The number of cylinders for this disk is set to %d.\n"
994 "There is nothing wrong with that, but this is larger than 1024,\n"
995 "and could in certain setups cause problems with:\n"
996 "1) software that runs at boot time (e.g., old versions of LILO)\n"
997 "2) booting and partitioning software from other OSs\n"
998 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1004 read_extended(int ext)
1008 struct partition *p, *q;
1012 pex->ext_pointer = pex->part_table;
1014 p = pex->part_table;
1015 if (!get_start_sect(p)) {
1016 printf("Bad offset in primary extended partition\n");
1020 while (IS_EXTENDED(p->sys_ind)) {
1021 struct pte *pe = &ptes[partitions];
1023 if (partitions >= MAXIMUM_PARTS) {
1024 /* This is not a Linux restriction, but
1025 this program uses arrays of size MAXIMUM_PARTS.
1026 Do not try to 'improve' this test. */
1027 struct pte *pre = &ptes[partitions-1];
1028 #if ENABLE_FEATURE_FDISK_WRITABLE
1029 printf("Warning: deleting partitions after %d\n",
1033 clear_partition(pre->ext_pointer);
1037 read_pte(pe, extended_offset + get_start_sect(p));
1039 if (!extended_offset)
1040 extended_offset = get_start_sect(p);
1042 q = p = pt_offset(pe->sectorbuffer, 0);
1043 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1044 if (IS_EXTENDED(p->sys_ind)) {
1045 if (pe->ext_pointer)
1046 printf("Warning: extra link "
1047 "pointer in partition table"
1048 " %d\n", partitions + 1);
1050 pe->ext_pointer = p;
1051 } else if (p->sys_ind) {
1053 printf("Warning: ignoring extra "
1054 "data in partition table"
1055 " %d\n", partitions + 1);
1061 /* very strange code here... */
1062 if (!pe->part_table) {
1063 if (q != pe->ext_pointer)
1066 pe->part_table = q + 1;
1068 if (!pe->ext_pointer) {
1069 if (q != pe->part_table)
1070 pe->ext_pointer = q;
1072 pe->ext_pointer = q + 1;
1075 p = pe->ext_pointer;
1079 #if ENABLE_FEATURE_FDISK_WRITABLE
1080 /* remove empty links */
1082 for (i = 4; i < partitions; i++) {
1083 struct pte *pe = &ptes[i];
1085 if (!get_nr_sects(pe->part_table)
1086 && (partitions > 5 || ptes[4].part_table->sys_ind)
1088 printf("Omitting empty partition (%d)\n", i+1);
1089 delete_partition(i);
1090 goto remove; /* numbering changed */
1096 #if ENABLE_FEATURE_FDISK_WRITABLE
1098 create_doslabel(void)
1102 printf(msg_building_new_label, "DOS disklabel");
1104 current_label_type = label_dos;
1106 #if ENABLE_FEATURE_OSF_LABEL
1107 possibly_osf_label = 0;
1111 for (i = 510-64; i < 510; i++)
1113 write_part_table_flag(MBRbuffer);
1114 extended_offset = 0;
1115 set_all_unchanged();
1117 get_boot(create_empty_dos);
1119 #endif /* FEATURE_FDISK_WRITABLE */
1122 get_sectorsize(void)
1124 if (!user_set_sector_size) {
1126 if (ioctl(fd, BLKSSZGET, &arg) == 0)
1128 if (sector_size != DEFAULT_SECTOR_SIZE)
1129 printf("Note: sector size is %d (not %d)\n",
1130 sector_size, DEFAULT_SECTOR_SIZE);
1135 get_kernel_geometry(void)
1137 struct hd_geometry geometry;
1139 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
1140 kern_heads = geometry.heads;
1141 kern_sectors = geometry.sectors;
1142 /* never use geometry.cylinders - it is truncated */
1147 get_partition_table_geometry(void)
1149 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1150 struct partition *p;
1151 int i, h, s, hh, ss;
1155 if (!(valid_part_table_flag((char*)bufp)))
1159 for (i = 0; i < 4; i++) {
1160 p = pt_offset(bufp, i);
1161 if (p->sys_ind != 0) {
1162 h = p->end_head + 1;
1163 s = (p->end_sector & 077);
1168 } else if (hh != h || ss != s)
1173 if (!first && !bad) {
1183 unsigned long long bytes; /* really u64 */
1186 sec_fac = sector_size / 512;
1187 #if ENABLE_FEATURE_SUN_LABEL
1188 guess_device_type();
1190 heads = cylinders = sectors = 0;
1191 kern_heads = kern_sectors = 0;
1192 pt_heads = pt_sectors = 0;
1194 get_kernel_geometry();
1195 get_partition_table_geometry();
1197 heads = user_heads ? user_heads :
1198 pt_heads ? pt_heads :
1199 kern_heads ? kern_heads : 255;
1200 sectors = user_sectors ? user_sectors :
1201 pt_sectors ? pt_sectors :
1202 kern_sectors ? kern_sectors : 63;
1203 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
1206 unsigned long longsectors;
1208 if (ioctl(fd, BLKGETSIZE, &longsectors))
1210 bytes = ((unsigned long long) longsectors) << 9;
1213 total_number_of_sectors = (bytes >> 9);
1216 if (dos_compatible_flag)
1217 sector_offset = sectors;
1219 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
1221 cylinders = user_cylinders;
1225 * Read MBR. Returns:
1226 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1227 * 0: found or created label
1231 get_boot(enum action what)
1237 for (i = 0; i < 4; i++) {
1238 struct pte *pe = &ptes[i];
1240 pe->part_table = pt_offset(MBRbuffer, i);
1241 pe->ext_pointer = NULL;
1243 pe->sectorbuffer = MBRbuffer;
1244 #if ENABLE_FEATURE_FDISK_WRITABLE
1245 pe->changed = (what == create_empty_dos);
1249 #if ENABLE_FEATURE_SUN_LABEL
1250 if (what == create_empty_sun && check_sun_label())
1254 memset(MBRbuffer, 0, 512);
1256 #if ENABLE_FEATURE_FDISK_WRITABLE
1257 if (what == create_empty_dos)
1258 goto got_dos_table; /* skip reading disk */
1260 fd = open(disk_device, type_open);
1262 fd = open(disk_device, O_RDONLY);
1264 if (what == try_only)
1266 fdisk_fatal(unable_to_open);
1268 printf("You will not be able to write "
1269 "the partition table\n");
1272 if (512 != read(fd, MBRbuffer, 512)) {
1273 if (what == try_only)
1275 fdisk_fatal(unable_to_read);
1278 fd = open(disk_device, O_RDONLY);
1281 if (512 != read(fd, MBRbuffer, 512))
1289 #if ENABLE_FEATURE_SUN_LABEL
1290 if (check_sun_label())
1294 #if ENABLE_FEATURE_SGI_LABEL
1295 if (check_sgi_label())
1299 #if ENABLE_FEATURE_AIX_LABEL
1300 if (check_aix_label())
1304 #if ENABLE_FEATURE_OSF_LABEL
1305 if (check_osf_label()) {
1306 possibly_osf_label = 1;
1307 if (!valid_part_table_flag(MBRbuffer)) {
1308 current_label_type = label_osf;
1311 printf("This disk has both DOS and BSD magic.\n"
1312 "Give the 'b' command to go to BSD mode.\n");
1316 #if ENABLE_FEATURE_FDISK_WRITABLE
1320 if (!valid_part_table_flag(MBRbuffer)) {
1321 #if !ENABLE_FEATURE_FDISK_WRITABLE
1326 printf("Device contains neither a valid DOS "
1327 "partition table, nor Sun, SGI or OSF "
1330 #if ENABLE_FEATURE_SUN_LABEL
1339 case create_empty_dos:
1340 #if ENABLE_FEATURE_SUN_LABEL
1341 case create_empty_sun:
1345 bb_error_msg_and_die("internal error");
1347 #endif /* FEATURE_FDISK_WRITABLE */
1350 #if ENABLE_FEATURE_FDISK_WRITABLE
1355 for (i = 0; i < 4; i++) {
1356 struct pte *pe = &ptes[i];
1358 if (IS_EXTENDED(pe->part_table->sys_ind)) {
1359 if (partitions != 4)
1360 printf("Ignoring extra extended "
1361 "partition %d\n", i + 1);
1367 for (i = 3; i < partitions; i++) {
1368 struct pte *pe = &ptes[i];
1370 if (!valid_part_table_flag(pe->sectorbuffer)) {
1371 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1372 "table %d will be corrected by w(rite)\n",
1373 pe->sectorbuffer[510],
1374 pe->sectorbuffer[511],
1376 #if ENABLE_FEATURE_FDISK_WRITABLE
1385 #if ENABLE_FEATURE_FDISK_WRITABLE
1387 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1388 * If the user hits Enter, DFLT is returned.
1389 * Answers like +10 are interpreted as offsets from BASE.
1391 * There is no default if DFLT is not between LOW and HIGH.
1394 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1398 const char *fmt = "%s (%u-%u, default %u): ";
1400 if (dflt < low || dflt > high) {
1401 fmt = "%s (%u-%u): ";
1406 int use_default = default_ok;
1408 /* ask question and read answer */
1410 printf(fmt, mesg, low, high, dflt);
1411 read_maybe_empty("");
1412 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1413 && *line_ptr != '-' && *line_ptr != '+');
1415 if (*line_ptr == '+' || *line_ptr == '-') {
1416 int minus = (*line_ptr == '-');
1419 i = atoi(line_ptr + 1);
1421 while (isdigit(*++line_ptr))
1424 switch (*line_ptr) {
1427 if (!display_in_cyl_units)
1428 i *= heads * sectors;
1442 absolute = 1000000000;
1448 unsigned long long bytes;
1451 bytes = (unsigned long long) i * absolute;
1452 unit = sector_size * units_per_sector;
1453 bytes += unit/2; /* round */
1462 while (isdigit(*line_ptr)) {
1469 printf("Using default value %u\n", i);
1471 if (i >= low && i <= high)
1473 printf("Value is out of range\n");
1479 get_partition(int warn, int max)
1484 i = read_int(1, 0, max, 0, "Partition number") - 1;
1488 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1489 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1490 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1492 printf("Warning: partition %d has empty type\n", i+1);
1499 get_existing_partition(int warn, int max)
1504 for (i = 0; i < max; i++) {
1505 struct pte *pe = &ptes[i];
1506 struct partition *p = pe->part_table;
1508 if (p && !is_cleared_partition(p)) {
1515 printf("Selected partition %d\n", pno+1);
1518 printf("No partition is defined yet!\n");
1522 return get_partition(warn, max);
1526 get_nonexisting_partition(int warn, int max)
1531 for (i = 0; i < max; i++) {
1532 struct pte *pe = &ptes[i];
1533 struct partition *p = pe->part_table;
1535 if (p && is_cleared_partition(p)) {
1542 printf("Selected partition %d\n", pno+1);
1545 printf("All primary partitions have been defined already!\n");
1549 return get_partition(warn, max);
1556 display_in_cyl_units = !display_in_cyl_units;
1558 printf("Changing display/entry units to %s\n",
1563 toggle_active(int i)
1565 struct pte *pe = &ptes[i];
1566 struct partition *p = pe->part_table;
1568 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1569 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1570 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1575 toggle_dos_compatibility_flag(void)
1577 dos_compatible_flag = ~dos_compatible_flag;
1578 if (dos_compatible_flag) {
1579 sector_offset = sectors;
1580 printf("DOS Compatibility flag is set\n");
1583 printf("DOS Compatibility flag is not set\n");
1588 delete_partition(int i)
1590 struct pte *pe = &ptes[i];
1591 struct partition *p = pe->part_table;
1592 struct partition *q = pe->ext_pointer;
1594 /* Note that for the fifth partition (i == 4) we don't actually
1595 * decrement partitions.
1598 if (warn_geometry())
1599 return; /* C/H/S not set */
1603 sun_delete_partition(i);
1607 sgi_delete_partition(i);
1612 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1614 ptes[ext_index].ext_pointer = NULL;
1615 extended_offset = 0;
1621 if (!q->sys_ind && i > 4) {
1622 /* the last one in the chain - just delete */
1625 clear_partition(ptes[i].ext_pointer);
1626 ptes[i].changed = 1;
1628 /* not the last one - further ones will be moved down */
1630 /* delete this link in the chain */
1631 p = ptes[i-1].ext_pointer;
1633 set_start_sect(p, get_start_sect(q));
1634 set_nr_sects(p, get_nr_sects(q));
1635 ptes[i-1].changed = 1;
1636 } else if (partitions > 5) { /* 5 will be moved to 4 */
1637 /* the first logical in a longer chain */
1640 if (pe->part_table) /* prevent SEGFAULT */
1641 set_start_sect(pe->part_table,
1642 get_partition_start(pe) -
1644 pe->offset = extended_offset;
1648 if (partitions > 5) {
1650 while (i < partitions) {
1651 ptes[i] = ptes[i+1];
1655 /* the only logical: clear only */
1656 clear_partition(ptes[i].part_table);
1663 int i, sys, origsys;
1664 struct partition *p;
1666 /* If sgi_label then don't use get_existing_partition,
1667 let the user select a partition, since get_existing_partition()
1668 only works for Linux like partition tables. */
1669 if (!LABEL_IS_SGI) {
1670 i = get_existing_partition(0, partitions);
1672 i = get_partition(0, partitions);
1676 p = ptes[i].part_table;
1677 origsys = sys = get_sysid(i);
1679 /* if changing types T to 0 is allowed, then
1680 the reverse change must be allowed, too */
1681 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1682 printf("Partition %d does not exist yet!\n", i + 1);
1686 sys = read_hex(get_sys_types());
1688 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1689 printf("Type 0 means free space to many systems\n"
1690 "(but not to Linux). Having partitions of\n"
1691 "type 0 is probably unwise.\n");
1695 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1696 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1697 printf("You cannot change a partition into"
1698 " an extended one or vice versa\n");
1704 #if ENABLE_FEATURE_SUN_LABEL
1705 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1706 printf("Consider leaving partition 3 "
1707 "as Whole disk (5),\n"
1708 "as SunOS/Solaris expects it and "
1709 "even Linux likes it\n\n");
1711 #if ENABLE_FEATURE_SGI_LABEL
1714 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1715 (i == 8 && sys != 0)
1718 printf("Consider leaving partition 9 "
1719 "as volume header (0),\nand "
1720 "partition 11 as entire volume (6)"
1721 "as IRIX expects it\n\n");
1727 sun_change_sysid(i, sys);
1728 } else if (LABEL_IS_SGI) {
1729 sgi_change_sysid(i, sys);
1733 printf("Changed system type of partition %d "
1734 "to %x (%s)\n", i + 1, sys,
1735 partition_type(sys));
1736 ptes[i].changed = 1;
1737 if (is_dos_partition(origsys) ||
1738 is_dos_partition(sys))
1744 #endif /* FEATURE_FDISK_WRITABLE */
1747 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1748 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1749 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1750 * Lubkin Oct. 1991). */
1753 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1755 int spc = heads * sectors;
1760 *s = ls % sectors + 1; /* sectors count from 1 */
1764 check_consistency(const struct partition *p, int partition)
1766 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1767 unsigned pec, peh, pes; /* physical ending c, h, s */
1768 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1769 unsigned lec, leh, les; /* logical ending c, h, s */
1771 if (!heads || !sectors || (partition >= 4))
1772 return; /* do not check extended partitions */
1774 /* physical beginning c, h, s */
1775 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1777 pbs = p->sector & 0x3f;
1779 /* physical ending c, h, s */
1780 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1782 pes = p->end_sector & 0x3f;
1784 /* compute logical beginning (c, h, s) */
1785 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1787 /* compute logical ending (c, h, s) */
1788 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1790 /* Same physical / logical beginning? */
1791 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1792 printf("Partition %d has different physical/logical "
1793 "beginnings (non-Linux?):\n", partition + 1);
1794 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1795 printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
1798 /* Same physical / logical ending? */
1799 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1800 printf("Partition %d has different physical/logical "
1801 "endings:\n", partition + 1);
1802 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1803 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1806 /* Ending on cylinder boundary? */
1807 if (peh != (heads - 1) || pes != sectors) {
1808 printf("Partition %i does not end on cylinder boundary\n",
1814 list_disk_geometry(void)
1816 long long bytes = (total_number_of_sectors << 9);
1817 long megabytes = bytes/1000000;
1819 if (megabytes < 10000)
1820 printf("\nDisk %s: %ld MB, %lld bytes\n",
1821 disk_device, megabytes, bytes);
1823 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1824 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1825 printf("%d heads, %d sectors/track, %d cylinders",
1826 heads, sectors, cylinders);
1827 if (units_per_sector == 1)
1828 printf(", total %llu sectors",
1829 total_number_of_sectors / (sector_size/512));
1830 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1832 units_per_sector, sector_size, units_per_sector * sector_size);
1836 * Check whether partition entries are ordered by their starting positions.
1837 * Return 0 if OK. Return i if partition i should have been earlier.
1838 * Two separate checks: primary and logical partitions.
1841 wrong_p_order(int *prev)
1843 const struct pte *pe;
1844 const struct partition *p;
1845 off_t last_p_start_pos = 0, p_start_pos;
1848 for (i = 0 ; i < partitions; i++) {
1851 last_p_start_pos = 0;
1854 if ((p = pe->part_table)->sys_ind) {
1855 p_start_pos = get_partition_start(pe);
1857 if (last_p_start_pos > p_start_pos) {
1863 last_p_start_pos = p_start_pos;
1870 #if ENABLE_FEATURE_FDISK_ADVANCED
1872 * Fix the chain of logicals.
1873 * extended_offset is unchanged, the set of sectors used is unchanged
1874 * The chain is sorted so that sectors increase, and so that
1875 * starting sectors increase.
1877 * After this it may still be that cfdisk doesnt like the table.
1878 * (This is because cfdisk considers expanded parts, from link to
1879 * end of partition, and these may still overlap.)
1881 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1885 fix_chain_of_logicals(void)
1887 int j, oj, ojj, sj, sjj;
1888 struct partition *pj,*pjj,tmp;
1890 /* Stage 1: sort sectors but leave sector of part 4 */
1891 /* (Its sector is the global extended_offset.) */
1893 for (j = 5; j < partitions-1; j++) {
1894 oj = ptes[j].offset;
1895 ojj = ptes[j+1].offset;
1897 ptes[j].offset = ojj;
1898 ptes[j+1].offset = oj;
1899 pj = ptes[j].part_table;
1900 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1901 pjj = ptes[j+1].part_table;
1902 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1903 set_start_sect(ptes[j-1].ext_pointer,
1904 ojj-extended_offset);
1905 set_start_sect(ptes[j].ext_pointer,
1906 oj-extended_offset);
1911 /* Stage 2: sort starting sectors */
1913 for (j = 4; j < partitions-1; j++) {
1914 pj = ptes[j].part_table;
1915 pjj = ptes[j+1].part_table;
1916 sj = get_start_sect(pj);
1917 sjj = get_start_sect(pjj);
1918 oj = ptes[j].offset;
1919 ojj = ptes[j+1].offset;
1920 if (oj+sj > ojj+sjj) {
1924 set_start_sect(pj, ojj+sjj-oj);
1925 set_start_sect(pjj, oj+sj-ojj);
1930 /* Probably something was changed */
1931 for (j = 4; j < partitions; j++)
1932 ptes[j].changed = 1;
1937 fix_partition_table_order(void)
1939 struct pte *pei, *pek;
1942 if (!wrong_p_order(NULL)) {
1943 printf("Ordering is already correct\n\n");
1947 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1948 /* partition i should have come earlier, move it */
1949 /* We have to move data in the MBR */
1950 struct partition *pi, *pk, *pe, pbuf;
1954 pe = pei->ext_pointer;
1955 pei->ext_pointer = pek->ext_pointer;
1956 pek->ext_pointer = pe;
1958 pi = pei->part_table;
1959 pk = pek->part_table;
1961 memmove(&pbuf, pi, sizeof(struct partition));
1962 memmove(pi, pk, sizeof(struct partition));
1963 memmove(pk, &pbuf, sizeof(struct partition));
1965 pei->changed = pek->changed = 1;
1969 fix_chain_of_logicals();
1977 list_table(int xtra)
1979 const struct partition *p;
1983 sun_list_table(xtra);
1987 sgi_list_table(xtra);
1991 list_disk_geometry();
1994 xbsd_print_disklabel(xtra);
1998 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
1999 but if the device name ends in a digit, say /dev/foo1,
2000 then the partition is called /dev/foo1p3. */
2001 w = strlen(disk_device);
2002 if (w && isdigit(disk_device[w-1]))
2007 // 1 12345678901 12345678901 12345678901 12
2008 printf("%*s Boot Start End Blocks Id System\n",
2011 for (i = 0; i < partitions; i++) {
2012 const struct pte *pe = &ptes[i];
2018 if (!p || is_cleared_partition(p))
2021 psects = get_nr_sects(p);
2025 if (sector_size < 1024) {
2026 pblocks /= (1024 / sector_size);
2027 podd = psects % (1024 / sector_size);
2029 if (sector_size > 1024)
2030 pblocks *= (sector_size / 1024);
2032 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2033 partname(disk_device, i+1, w+2),
2034 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2036 (unsigned long long) cround(get_partition_start(pe)), /* start */
2037 (unsigned long long) cround(get_partition_start(pe) + psects /* end */
2038 - (psects ? 1 : 0)),
2039 (unsigned long long) pblocks, podd ? '+' : ' ', /* odd flag on end */
2040 p->sys_ind, /* type id */
2041 partition_type(p->sys_ind)); /* type name */
2043 check_consistency(p, i);
2046 /* Is partition table in disk order? It need not be, but... */
2047 /* partition table entries are not checked for correct order if this
2048 is a sgi, sun or aix labeled disk... */
2049 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2051 printf("\nPartition table entries are not in disk order\n");
2055 #if ENABLE_FEATURE_FDISK_ADVANCED
2057 x_list_table(int extend)
2059 const struct pte *pe;
2060 const struct partition *p;
2063 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2064 disk_device, heads, sectors, cylinders);
2065 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2066 for (i = 0 ; i < partitions; i++) {
2068 p = (extend ? pe->ext_pointer : pe->part_table);
2070 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2071 i + 1, p->boot_ind, p->head,
2073 cylinder(p->sector, p->cyl), p->end_head,
2074 sector(p->end_sector),
2075 cylinder(p->end_sector, p->end_cyl),
2076 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2078 check_consistency(p, i);
2084 #if ENABLE_FEATURE_FDISK_WRITABLE
2086 fill_bounds(off_t *first, off_t *last)
2089 const struct pte *pe = &ptes[0];
2090 const struct partition *p;
2092 for (i = 0; i < partitions; pe++,i++) {
2094 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2095 first[i] = 0xffffffff;
2098 first[i] = get_partition_start(pe);
2099 last[i] = first[i] + get_nr_sects(p) - 1;
2105 check(int n, unsigned h, unsigned s, unsigned c, off_t start)
2107 off_t total, real_s, real_c;
2109 real_s = sector(s) - 1;
2110 real_c = cylinder(s, c);
2111 total = (real_c * sectors + real_s) * heads + h;
2113 printf("Partition %d contains sector 0\n", n);
2115 printf("Partition %d: head %d greater than maximum %d\n",
2117 if (real_s >= sectors)
2118 printf("Partition %d: sector %d greater than "
2119 "maximum %d\n", n, s, sectors);
2120 if (real_c >= cylinders)
2121 printf("Partition %d: cylinder %"OFF_FMT"u greater than "
2122 "maximum %d\n", n, real_c + 1, cylinders);
2123 if (cylinders <= 1024 && start != total)
2124 printf("Partition %d: previous sectors %"OFF_FMT"u disagrees with "
2125 "total %"OFF_FMT"u\n", n, start, total);
2133 off_t first[partitions], last[partitions];
2134 struct partition *p;
2136 if (warn_geometry())
2148 fill_bounds(first, last);
2149 for (i = 0; i < partitions; i++) {
2150 struct pte *pe = &ptes[i];
2153 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2154 check_consistency(p, i);
2155 if (get_partition_start(pe) < first[i])
2156 printf("Warning: bad start-of-data in "
2157 "partition %d\n", i + 1);
2158 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2160 total += last[i] + 1 - first[i];
2161 for (j = 0; j < i; j++) {
2162 if ((first[i] >= first[j] && first[i] <= last[j])
2163 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2164 printf("Warning: partition %d overlaps "
2165 "partition %d\n", j + 1, i + 1);
2166 total += first[i] >= first[j] ?
2167 first[i] : first[j];
2168 total -= last[i] <= last[j] ?
2175 if (extended_offset) {
2176 struct pte *pex = &ptes[ext_index];
2177 off_t e_last = get_start_sect(pex->part_table) +
2178 get_nr_sects(pex->part_table) - 1;
2180 for (i = 4; i < partitions; i++) {
2182 p = ptes[i].part_table;
2184 if (i != 4 || i + 1 < partitions)
2185 printf("Warning: partition %d "
2186 "is empty\n", i + 1);
2187 } else if (first[i] < extended_offset || last[i] > e_last) {
2188 printf("Logical partition %d not entirely in "
2189 "partition %d\n", i + 1, ext_index + 1);
2194 if (total > heads * sectors * cylinders)
2195 printf("Total allocated sectors %d greater than the maximum "
2196 "%d\n", total, heads * sectors * cylinders);
2198 total = heads * sectors * cylinders - total;
2200 printf("%d unallocated sectors\n", total);
2205 add_partition(int n, int sys)
2207 char mesg[256]; /* 48 does not suffice in Japanese */
2208 int i, num_read = 0;
2209 struct partition *p = ptes[n].part_table;
2210 struct partition *q = ptes[ext_index].part_table;
2212 off_t start, stop = 0, limit, temp,
2213 first[partitions], last[partitions];
2215 if (p && p->sys_ind) {
2216 printf(msg_part_already_defined, n + 1);
2219 fill_bounds(first, last);
2221 start = sector_offset;
2222 if (display_in_cyl_units || !total_number_of_sectors)
2223 llimit = heads * sectors * cylinders - 1;
2225 llimit = total_number_of_sectors - 1;
2227 if (limit != llimit)
2229 if (extended_offset) {
2230 first[ext_index] = extended_offset;
2231 last[ext_index] = get_start_sect(q) +
2232 get_nr_sects(q) - 1;
2235 start = extended_offset + sector_offset;
2236 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2238 if (display_in_cyl_units)
2239 for (i = 0; i < partitions; i++)
2240 first[i] = (cround(first[i]) - 1) * units_per_sector;
2242 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2245 for (i = 0; i < partitions; i++) {
2248 if (start == ptes[i].offset)
2249 start += sector_offset;
2250 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2251 if (start >= first[i] && start <= lastplusoff)
2252 start = lastplusoff + 1;
2256 if (start >= temp+units_per_sector && num_read) {
2257 printf("Sector %"OFF_FMT"d is already allocated\n", temp);
2261 if (!num_read && start == temp) {
2264 saved_start = start;
2265 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2267 if (display_in_cyl_units) {
2268 start = (start - 1) * units_per_sector;
2269 if (start < saved_start) start = saved_start;
2273 } while (start != temp || !num_read);
2274 if (n > 4) { /* NOT for fifth partition */
2275 struct pte *pe = &ptes[n];
2277 pe->offset = start - sector_offset;
2278 if (pe->offset == extended_offset) { /* must be corrected */
2280 if (sector_offset == 1)
2285 for (i = 0; i < partitions; i++) {
2286 struct pte *pe = &ptes[i];
2288 if (start < pe->offset && limit >= pe->offset)
2289 limit = pe->offset - 1;
2290 if (start < first[i] && limit >= first[i])
2291 limit = first[i] - 1;
2293 if (start > limit) {
2294 printf("No free sectors available\n");
2299 if (cround(start) == cround(limit)) {
2302 snprintf(mesg, sizeof(mesg),
2303 "Last %s or +size or +sizeM or +sizeK",
2304 str_units(SINGULAR));
2305 stop = read_int(cround(start), cround(limit), cround(limit),
2306 cround(start), mesg);
2307 if (display_in_cyl_units) {
2308 stop = stop * units_per_sector - 1;
2314 set_partition(n, 0, start, stop, sys);
2316 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2318 if (IS_EXTENDED(sys)) {
2319 struct pte *pe4 = &ptes[4];
2320 struct pte *pen = &ptes[n];
2323 pen->ext_pointer = p;
2324 pe4->offset = extended_offset = start;
2325 pe4->sectorbuffer = xzalloc(sector_size);
2326 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2327 pe4->ext_pointer = pe4->part_table + 1;
2336 if (partitions > 5 || ptes[4].part_table->sys_ind) {
2337 struct pte *pe = &ptes[partitions];
2339 pe->sectorbuffer = xzalloc(sector_size);
2340 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2341 pe->ext_pointer = pe->part_table + 1;
2346 add_partition(partitions - 1, LINUX_NATIVE);
2352 int i, free_primary = 0;
2354 if (warn_geometry())
2358 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
2362 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
2366 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2367 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2368 "table first (use 'o'). This will destroy the present disk contents.\n");
2372 for (i = 0; i < 4; i++)
2373 free_primary += !ptes[i].part_table->sys_ind;
2375 if (!free_primary && partitions >= MAXIMUM_PARTS) {
2376 printf("The maximum number of partitions has been created\n");
2380 if (!free_primary) {
2381 if (extended_offset)
2384 printf("You must delete some partition and add "
2385 "an extended partition first\n");
2388 snprintf(line, sizeof(line),
2391 " p primary partition (1-4)\n",
2393 "l logical (5 or over)" : "e extended"));
2395 c = read_nonempty(line);
2396 if (c == 'p' || c == 'P') {
2397 i = get_nonexisting_partition(0, 4);
2399 add_partition(i, LINUX_NATIVE);
2402 if (c == 'l' && extended_offset) {
2406 if (c == 'e' && !extended_offset) {
2407 i = get_nonexisting_partition(0, 4);
2409 add_partition(i, EXTENDED);
2412 printf("Invalid partition number "
2413 "for type '%c'\n", c);
2424 for (i = 0; i < 3; i++)
2425 if (ptes[i].changed)
2426 ptes[3].changed = 1;
2427 for (i = 3; i < partitions; i++) {
2428 struct pte *pe = &ptes[i];
2431 write_part_table_flag(pe->sectorbuffer);
2432 write_sector(pe->offset, pe->sectorbuffer);
2436 else if (LABEL_IS_SGI) {
2437 /* no test on change? the printf below might be mistaken */
2440 else if (LABEL_IS_SUN) {
2443 for (i = 0; i < 8; i++)
2444 if (ptes[i].changed)
2450 printf("The partition table has been altered!\n\n");
2451 reread_partition_table(1);
2455 reread_partition_table(int leave)
2459 printf("Calling ioctl() to re-read partition table\n");
2461 /* sleep(2); Huh? */
2462 i = ioctl(fd, BLKRRPART);
2465 /* some kernel versions (1.2.x) seem to have trouble
2466 rereading the partition table, but if asked to do it
2467 twice, the second time works. - biro@yggdrasil.com */
2470 i = ioctl(fd, BLKRRPART);
2475 bb_perror_msg("WARNING: rereading partition table "
2476 "failed, kernel still uses old table");
2482 "\nWARNING: If you have created or modified any DOS 6.x\n"
2483 "partitions, please see the fdisk manual page for additional\n"
2488 if (ENABLE_FEATURE_CLEAN_UP)
2493 #endif /* FEATURE_FDISK_WRITABLE */
2495 #if ENABLE_FEATURE_FDISK_ADVANCED
2496 #define MAX_PER_LINE 16
2498 print_buffer(char *pbuffer)
2502 for (i = 0, l = 0; i < sector_size; i++, l++) {
2504 printf("0x%03X:", i);
2505 printf(" %02X", (unsigned char) pbuffer[i]);
2506 if (l == MAX_PER_LINE - 1) {
2521 printf("Device: %s\n", disk_device);
2522 if (LABEL_IS_SGI || LABEL_IS_SUN)
2523 print_buffer(MBRbuffer);
2525 for (i = 3; i < partitions; i++)
2526 print_buffer(ptes[i].sectorbuffer);
2533 struct pte *pe = &ptes[i];
2534 struct partition *p = pe->part_table;
2537 if (warn_geometry())
2539 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2540 printf("Partition %d has no data area\n", i + 1);
2543 first = get_partition_start(pe);
2544 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2545 "New beginning of data") - pe->offset;
2547 if (new != get_nr_sects(p)) {
2548 first = get_nr_sects(p) + get_start_sect(p) - new;
2549 set_nr_sects(p, first);
2550 set_start_sect(p, new);
2562 c = tolower(read_nonempty("Expert command (m for help): "));
2570 move_begin(get_partition(0, partitions));
2573 user_cylinders = cylinders =
2574 read_int(1, cylinders, 1048576, 0,
2575 "Number of cylinders");
2577 sun_set_ncyl(cylinders);
2587 else if (LABEL_IS_SUN)
2589 else if (LABEL_IS_DOS)
2594 fix_partition_table_order();
2597 #if ENABLE_FEATURE_SGI_LABEL
2602 user_heads = heads = read_int(1, heads, 256, 0,
2627 user_sectors = sectors = read_int(1, sectors, 63, 0,
2628 "Number of sectors");
2629 if (dos_compatible_flag) {
2630 sector_offset = sectors;
2631 printf("Warning: setting sector offset for DOS "
2640 write_table(); /* does not return */
2644 sun_set_pcylcount();
2651 #endif /* ADVANCED mode */
2654 is_ide_cdrom_or_tape(const char *device)
2658 struct stat statbuf;
2661 /* No device was given explicitly, and we are trying some
2662 likely things. But opening /dev/hdc may produce errors like
2663 "hdc: tray open or drive not ready"
2664 if it happens to be a CD-ROM drive. It even happens that
2665 the process hangs on the attempt to read a music CD.
2666 So try to be careful. This only works since 2.1.73. */
2668 if (strncmp("/dev/hd", device, 7))
2671 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2672 procf = fopen(buf, "r");
2673 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2674 is_ide = (!strncmp(buf, "cdrom", 5) ||
2675 !strncmp(buf, "tape", 4));
2677 /* Now when this proc file does not exist, skip the
2678 device when it is read-only. */
2679 if (stat(device, &statbuf) == 0)
2680 is_ide = ((statbuf.st_mode & 0222) == 0);
2689 trydev(const char *device, int user_specified)
2693 disk_device = device;
2694 if (setjmp(listingbuf))
2696 if (!user_specified)
2697 if (is_ide_cdrom_or_tape(device))
2699 fd = open(disk_device, type_open);
2701 gb = get_boot(try_only);
2702 if (gb > 0) { /* I/O error */
2704 } else if (gb < 0) { /* no DOS signature */
2705 list_disk_geometry();
2709 #if ENABLE_FEATURE_OSF_LABEL
2710 if (bsd_trydev(device) < 0)
2712 printf("Disk %s doesn't contain a valid "
2713 "partition table\n", device);
2718 #if ENABLE_FEATURE_FDISK_WRITABLE
2719 if (!LABEL_IS_SUN && partitions > 4){
2720 delete_partition(ext_index);
2725 /* Ignore other errors, since we try IDE
2726 and SCSI hard disks which may not be
2727 installed on the system. */
2728 if (errno == EACCES) {
2729 printf("Cannot open %s\n", device);
2735 /* for fdisk -l: try all things in /proc/partitions
2736 that look like a partition name (do not end in a digit) */
2741 char line[100], ptname[100], devname[120], *s;
2744 procpt = fopen_or_warn("/proc/partitions", "r");
2746 while (fgets(line, sizeof(line), procpt)) {
2747 if (sscanf(line, " %d %d %d %[^\n ]",
2748 &ma, &mi, &sz, ptname) != 4)
2750 for (s = ptname; *s; s++);
2753 sprintf(devname, "/dev/%s", ptname);
2756 #if ENABLE_FEATURE_CLEAN_UP
2761 #if ENABLE_FEATURE_FDISK_WRITABLE
2763 unknown_command(int c)
2765 printf("%c: unknown command\n", c);
2769 int fdisk_main(int argc, char **argv);
2770 int fdisk_main(int argc, char **argv)
2772 char *str_b, *str_C, *str_H, *str_S;
2776 * fdisk -l [-b sectorsize] [-u] device ...
2777 * fdisk -s [partition] ...
2778 * fdisk [-b sectorsize] [-u] device
2780 * Options -C, -H, -S set the geometry.
2789 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
2792 PTR_TO_GLOBALS = xzalloc(sizeof(G));
2794 opt = getopt32(argc, argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2795 &str_b, &str_C, &str_H, &str_S);
2798 if (opt & OPT_b) { // -b
2799 /* Ugly: this sector size is really per device,
2800 so cannot be combined with multiple disks,
2801 and the same goes for the C/H/S options.
2803 sector_size = xatoi_u(str_b);
2804 if (sector_size != 512 && sector_size != 1024 &&
2805 sector_size != 2048)
2808 user_set_sector_size = 1;
2810 if (opt & OPT_C) user_cylinders = xatoi_u(str_C); // -C
2811 if (opt & OPT_H) { // -H
2812 user_heads = xatoi_u(str_H);
2813 if (user_heads <= 0 || user_heads >= 256)
2816 //if (opt & OPT_l) // -l
2817 if (opt & OPT_S) { // -S
2818 user_sectors = xatoi_u(str_S);
2819 if (user_sectors <= 0 || user_sectors >= 64)
2822 if (opt & OPT_u) display_in_cyl_units = 0; // -u
2823 //if (opt & OPT_s) // -s
2825 if (user_set_sector_size && argc != 1)
2826 printf("Warning: the -b (set sector size) option should"
2827 " be used with one specified device\n");
2829 #if ENABLE_FEATURE_FDISK_WRITABLE
2833 type_open = O_RDONLY;
2836 #if defined(__GNUC__)
2837 /* avoid gcc warning:
2838 variable `k' might be clobbered by `longjmp' */
2842 for (k = 0; k < argc; k++)
2845 /* we no longer have default device names */
2846 /* but, we can use /proc/partitions instead */
2850 #if ENABLE_FEATURE_FDISK_WRITABLE
2854 #if ENABLE_FEATURE_FDISK_BLKSIZE
2860 type_open = O_RDONLY;
2865 for (j = 0; j < argc; j++) {
2866 disk_device = argv[j];
2867 fd = open(disk_device, type_open);
2869 fdisk_fatal(unable_to_open);
2870 if (ioctl(fd, BLKGETSIZE, &size))
2871 fdisk_fatal(ioctl_error);
2874 printf("%ld\n", size/2);
2876 printf("%s: %ld\n", argv[j], size/2);
2882 #if ENABLE_FEATURE_FDISK_WRITABLE
2886 disk_device = argv[0];
2890 /* OSF label, and no DOS label */
2891 printf("Detected an OSF/1 disklabel on %s, entering "
2892 "disklabel mode\n", disk_device);
2894 /*Why do we do this? It seems to be counter-intuitive*/
2895 current_label_type = label_dos;
2896 /* If we return we may want to make an empty DOS label? */
2902 c = tolower(read_nonempty("Command (m for help): "));
2906 toggle_active(get_partition(1, partitions));
2907 else if (LABEL_IS_SUN)
2908 toggle_sunflags(get_partition(1, partitions),
2910 else if (LABEL_IS_SGI)
2911 sgi_set_bootpartition(
2912 get_partition(1, partitions));
2918 printf("\nThe current boot file is: %s\n",
2919 sgi_get_bootfile());
2920 if (read_maybe_empty("Please enter the name of the "
2921 "new boot file: ") == '\n')
2922 printf("Boot file unchanged\n");
2924 sgi_set_bootfile(line_ptr);
2926 #if ENABLE_FEATURE_OSF_LABEL
2933 toggle_dos_compatibility_flag();
2934 else if (LABEL_IS_SUN)
2935 toggle_sunflags(get_partition(1, partitions),
2937 else if (LABEL_IS_SGI)
2938 sgi_set_swappartition(
2939 get_partition(1, partitions));
2946 /* If sgi_label then don't use get_existing_partition,
2947 let the user select a partition, since
2948 get_existing_partition() only works for Linux-like
2950 if (!LABEL_IS_SGI) {
2951 j = get_existing_partition(1, partitions);
2953 j = get_partition(1, partitions);
2956 delete_partition(j);
2965 list_types(get_sys_types());
2984 #if ENABLE_FEATURE_SUN_LABEL
2998 write_table(); /* does not return */
3000 #if ENABLE_FEATURE_FDISK_ADVANCED
3003 printf("\n\tSorry, no experts menu for SGI "
3004 "partition tables available\n\n");
3015 #endif /* FEATURE_FDISK_WRITABLE */