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 #ifndef _LARGEFILE64_SOURCE
12 #define _LARGEFILE64_SOURCE
14 #include <assert.h> /* assert */
17 /* Looks like someone forgot to add this to config system */
18 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
19 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
20 # define USE_FEATURE_FDISK_BLKSIZE(a)
23 #define DEFAULT_SECTOR_SIZE 512
24 #define MAX_SECTOR_SIZE 2048
25 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
26 #define MAXIMUM_PARTS 60
28 #define ACTIVE_FLAG 0x80
31 #define WIN98_EXTENDED 0x0f
32 #define LINUX_PARTITION 0x81
33 #define LINUX_SWAP 0x82
34 #define LINUX_NATIVE 0x83
35 #define LINUX_EXTENDED 0x85
36 #define LINUX_LVM 0x8e
37 #define LINUX_RAID 0xfd
39 /* Used for sector numbers. Today's disk sizes make it necessary */
40 typedef unsigned long long ullong;
44 unsigned char sectors;
45 unsigned short cylinders;
49 #define HDIO_GETGEO 0x0301 /* get device geometry */
51 static const char msg_building_new_label[] ALIGN1 =
52 "Building a new %s. Changes will remain in memory only,\n"
53 "until you decide to write them. After that the previous content\n"
54 "won't be recoverable.\n\n";
56 static const char msg_part_already_defined[] ALIGN1 =
57 "Partition %d is already defined, delete it before re-adding\n";
61 unsigned char boot_ind; /* 0x80 - active */
62 unsigned char head; /* starting head */
63 unsigned char sector; /* starting sector */
64 unsigned char cyl; /* starting cylinder */
65 unsigned char sys_ind; /* What partition type */
66 unsigned char end_head; /* end head */
67 unsigned char end_sector; /* end sector */
68 unsigned char end_cyl; /* end cylinder */
69 unsigned char start4[4]; /* starting sector counting from 0 */
70 unsigned char size4[4]; /* nr of sectors in partition */
73 static const char unable_to_open[] ALIGN1 = "cannot open %s";
74 static const char unable_to_read[] ALIGN1 = "cannot read from %s";
75 static const char unable_to_seek[] ALIGN1 = "cannot seek on %s";
76 static const char unable_to_write[] ALIGN1 = "cannot write to %s";
77 static const char ioctl_error[] ALIGN1 = "BLKGETSIZE ioctl failed on %s";
78 static void fdisk_fatal(const char *why) ATTRIBUTE_NORETURN;
81 label_dos, label_sun, label_sgi, label_aix, label_osf
84 #define LABEL_IS_DOS (label_dos == current_label_type)
86 #if ENABLE_FEATURE_SUN_LABEL
87 #define LABEL_IS_SUN (label_sun == current_label_type)
88 #define STATIC_SUN static
90 #define LABEL_IS_SUN 0
91 #define STATIC_SUN extern
94 #if ENABLE_FEATURE_SGI_LABEL
95 #define LABEL_IS_SGI (label_sgi == current_label_type)
96 #define STATIC_SGI static
98 #define LABEL_IS_SGI 0
99 #define STATIC_SGI extern
102 #if ENABLE_FEATURE_AIX_LABEL
103 #define LABEL_IS_AIX (label_aix == current_label_type)
104 #define STATIC_AIX static
106 #define LABEL_IS_AIX 0
107 #define STATIC_AIX extern
110 #if ENABLE_FEATURE_OSF_LABEL
111 #define LABEL_IS_OSF (label_osf == current_label_type)
112 #define STATIC_OSF static
114 #define LABEL_IS_OSF 0
115 #define STATIC_OSF extern
118 enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
120 static void update_units(void);
121 #if ENABLE_FEATURE_FDISK_WRITABLE
122 static void change_units(void);
123 static void reread_partition_table(int leave);
124 static void delete_partition(int i);
125 static int get_partition(int warn, int max);
126 static void list_types(const char *const *sys);
127 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
129 static const char *partition_type(unsigned char type);
130 static void get_geometry(void);
131 static int get_boot(enum action what);
136 static unsigned get_start_sect(const struct partition *p);
137 static unsigned get_nr_sects(const struct partition *p);
140 * per partition table entry data
142 * The four primary partitions have the same sectorbuffer (MBRbuffer)
143 * and have NULL ext_pointer.
144 * Each logical partition table entry has two pointers, one for the
145 * partition and one link to the next one.
148 struct partition *part_table; /* points into sectorbuffer */
149 struct partition *ext_pointer; /* points into sectorbuffer */
150 ullong offset; /* disk sector number */
151 char *sectorbuffer; /* disk sector contents */
152 #if ENABLE_FEATURE_FDISK_WRITABLE
153 char changed; /* boolean */
157 /* DOS partition types */
159 static const char *const i386_sys_types[] = {
163 "\x05" "Extended", /* DOS 3.3+ extended partition */
164 "\x06" "FAT16", /* DOS 16-bit >=32M */
165 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
166 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
167 "\x0b" "Win95 FAT32",
168 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
169 "\x0e" "Win95 FAT16 (LBA)",
170 "\x0f" "Win95 Ext'd (LBA)",
171 "\x11" "Hidden FAT12",
172 "\x12" "Compaq diagnostics",
173 "\x14" "Hidden FAT16 <32M",
174 "\x16" "Hidden FAT16",
175 "\x17" "Hidden HPFS/NTFS",
176 "\x1b" "Hidden Win95 FAT32",
177 "\x1c" "Hidden W95 FAT32 (LBA)",
178 "\x1e" "Hidden W95 FAT16 (LBA)",
179 "\x3c" "Part.Magic recovery",
180 "\x41" "PPC PReP Boot",
182 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
183 "\x80" "Old Minix", /* Minix 1.4a and earlier */
184 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
185 "\x82" "Linux swap", /* also Solaris */
187 "\x84" "OS/2 hidden C: drive",
188 "\x85" "Linux extended",
189 "\x86" "NTFS volume set",
190 "\x87" "NTFS volume set",
192 "\x9f" "BSD/OS", /* BSDI */
193 "\xa0" "Thinkpad hibernation",
194 "\xa5" "FreeBSD", /* various BSD flavours */
198 "\xab" "Darwin boot",
201 "\xbe" "Solaris boot",
203 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
204 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
205 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
206 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
207 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
208 autodetect using persistent
210 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
213 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
214 "\x09" "AIX bootable", /* AIX data or Coherent */
216 "\x18" "AST SmartSleep",
219 "\x40" "Venix 80286",
221 "\x4e" "QNX4.x 2nd part",
222 "\x4f" "QNX4.x 3rd part",
224 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
225 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
226 "\x53" "OnTrack DM6 Aux3",
230 "\x5c" "Priam Edisk",
232 "\x64" "Novell Netware 286",
233 "\x65" "Novell Netware 386",
234 "\x70" "DiskSecure Multi-Boot",
237 "\x94" "Amoeba BBT", /* (bad block table) */
239 "\xbb" "Boot Wizard hidden",
240 "\xc1" "DRDOS/sec (FAT-12)",
241 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
242 "\xc6" "DRDOS/sec (FAT-16)",
244 "\xda" "Non-FS data",
245 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
246 Concurrent DOS or CTOS */
247 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
248 "\xdf" "BootIt", /* BootIt EMBRM */
249 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
250 extended partition */
251 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
252 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
253 partition < 1024 cyl. */
255 "\xf4" "SpeedStor", /* SpeedStor large partition */
256 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
257 "\xff" "BBT", /* Xenix Bad Block Table */
268 const char *disk_device;
269 int fd; /* the disk */
270 int g_partitions; // = 4; /* maximum partition + 1 */
271 unsigned units_per_sector; // = 1;
272 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
273 unsigned user_set_sector_size;
274 unsigned sector_offset; // = 1;
275 unsigned g_heads, g_sectors, g_cylinders;
276 enum label_type current_label_type;
277 smallint display_in_cyl_units; // = 1;
278 #if ENABLE_FEATURE_OSF_LABEL
279 smallint possibly_osf_label;
283 char line_buffer[80];
284 char partname_buffer[80];
285 /* Raw disk label. For DOS-type partition tables the MBR,
286 * with descriptions of the primary partitions. */
287 char MBRbuffer[MAX_SECTOR_SIZE];
288 /* Partition tables */
289 struct pte ptes[MAXIMUM_PARTS];
291 #define G (*ptr_to_globals)
292 #define line_ptr (G.line_ptr)
293 #define disk_device (G.disk_device )
295 #define g_partitions (G.g_partitions )
296 #define units_per_sector (G.units_per_sector )
297 #define sector_size (G.sector_size )
298 #define user_set_sector_size (G.user_set_sector_size)
299 #define sector_offset (G.sector_offset )
300 #define g_heads (G.g_heads )
301 #define g_sectors (G.g_sectors )
302 #define g_cylinders (G.g_cylinders )
303 #define current_label_type (G.current_label_type )
304 #define display_in_cyl_units (G.display_in_cyl_units)
305 #define possibly_osf_label (G.possibly_osf_label )
306 #define listingbuf (G.listingbuf)
307 #define line_buffer (G.line_buffer)
308 #define partname_buffer (G.partname_buffer)
309 #define MBRbuffer (G.MBRbuffer)
310 #define ptes (G.ptes)
311 #define INIT_G() do { \
312 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
313 sector_size = DEFAULT_SECTOR_SIZE; \
316 display_in_cyl_units = 1; \
317 units_per_sector = 1; \
321 /* TODO: move to libbb? */
322 static ullong bb_BLKGETSIZE_sectors(void)
325 unsigned long longsectors;
327 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
328 /* got bytes, convert to 512 byte sectors */
331 /* Needs temp of type long */
332 if (ioctl(fd, BLKGETSIZE, &longsectors))
338 #define IS_EXTENDED(i) \
339 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
341 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
343 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
345 #define pt_offset(b, n) \
346 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
348 #define sector(s) ((s) & 0x3f)
350 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
352 #define hsc2sector(h,s,c) \
353 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
355 #define set_hsc(h,s,c,sector) \
357 s = sector % g_sectors + 1; \
358 sector /= g_sectors; \
359 h = sector % g_heads; \
362 s |= (sector >> 2) & 0xc0; \
365 #if ENABLE_FEATURE_FDISK_WRITABLE
366 /* read line; return 0 or first printable char */
368 read_line(const char *prompt)
372 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
374 exit(0); /* Ctrl-D or Ctrl-C */
376 if (line_buffer[sz-1] == '\n')
377 line_buffer[--sz] = '\0';
379 line_ptr = line_buffer;
380 while (*line_ptr && !isgraph(*line_ptr))
387 * return partition name - uses static storage
390 partname(const char *dev, int pno, int lth)
397 bufp = partname_buffer;
398 bufsiz = sizeof(partname_buffer);
403 if (isdigit(dev[w-1]))
406 /* devfs kludge - note: fdisk partition names are not supposed
407 to equal kernel names, so there is no reason to do this */
408 if (strcmp(dev + w - 4, "disc") == 0) {
416 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
417 lth-wp-2, w, dev, p, pno);
419 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
424 #if ENABLE_FEATURE_FDISK_WRITABLE
426 set_all_unchanged(void)
430 for (i = 0; i < MAXIMUM_PARTS; i++)
434 static ALWAYS_INLINE void
439 #endif /* FEATURE_FDISK_WRITABLE */
441 static ALWAYS_INLINE struct partition *
442 get_part_table(int i)
444 return ptes[i].part_table;
449 { /* n==1: use singular */
451 return display_in_cyl_units ? "cylinder" : "sector";
452 return display_in_cyl_units ? "cylinders" : "sectors";
456 valid_part_table_flag(const char *mbuffer)
458 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
461 #if ENABLE_FEATURE_FDISK_WRITABLE
462 static ALWAYS_INLINE void
463 write_part_table_flag(char *b)
470 read_nonempty(const char *mesg)
472 while (!read_line(mesg)) /* repeat */;
477 read_maybe_empty(const char *mesg)
479 if (!read_line(mesg)) {
480 line_ptr = line_buffer;
488 read_hex(const char *const *sys)
492 read_nonempty("Hex code (type L to list codes): ");
493 if (*line_ptr == 'l' || *line_ptr == 'L') {
497 v = bb_strtoul(line_ptr, NULL, 16);
499 /* Bad input also triggers this */
504 #endif /* FEATURE_FDISK_WRITABLE */
506 #include "fdisk_aix.c"
509 unsigned char info[128]; /* Informative text string */
510 unsigned char spare0[14];
512 unsigned char spare1;
514 unsigned char spare2;
517 unsigned char spare1[246]; /* Boot information etc. */
518 unsigned short rspeed; /* Disk rotational speed */
519 unsigned short pcylcount; /* Physical cylinder count */
520 unsigned short sparecyl; /* extra sects per cylinder */
521 unsigned char spare2[4]; /* More magic... */
522 unsigned short ilfact; /* Interleave factor */
523 unsigned short ncyl; /* Data cylinder count */
524 unsigned short nacyl; /* Alt. cylinder count */
525 unsigned short ntrks; /* Tracks per cylinder */
526 unsigned short nsect; /* Sectors per track */
527 unsigned char spare3[4]; /* Even more magic... */
528 struct sun_partinfo {
529 uint32_t start_cylinder;
530 uint32_t num_sectors;
532 unsigned short magic; /* Magic number */
533 unsigned short csum; /* Label xor'd checksum */
535 #define sunlabel ((sun_partition *)MBRbuffer)
536 STATIC_OSF void bsd_select(void);
537 STATIC_OSF void xbsd_print_disklabel(int);
538 #include "fdisk_osf.c"
540 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
542 fdisk_swap16(uint16_t x)
544 return (x << 8) | (x >> 8);
548 fdisk_swap32(uint32_t x)
551 ((x & 0xFF00) << 8) |
552 ((x & 0xFF0000) >> 8) |
557 STATIC_SGI const char *const sgi_sys_types[];
558 STATIC_SGI unsigned sgi_get_num_sectors(int i);
559 STATIC_SGI int sgi_get_sysid(int i);
560 STATIC_SGI void sgi_delete_partition(int i);
561 STATIC_SGI void sgi_change_sysid(int i, int sys);
562 STATIC_SGI void sgi_list_table(int xtra);
563 #if ENABLE_FEATURE_FDISK_ADVANCED
564 STATIC_SGI void sgi_set_xcyl(void);
566 STATIC_SGI int verify_sgi(int verbose);
567 STATIC_SGI void sgi_add_partition(int n, int sys);
568 STATIC_SGI void sgi_set_swappartition(int i);
569 STATIC_SGI const char *sgi_get_bootfile(void);
570 STATIC_SGI void sgi_set_bootfile(const char* aFile);
571 STATIC_SGI void create_sgiinfo(void);
572 STATIC_SGI void sgi_write_table(void);
573 STATIC_SGI void sgi_set_bootpartition(int i);
574 #include "fdisk_sgi.c"
576 STATIC_SUN const char *const sun_sys_types[];
577 STATIC_SUN void sun_delete_partition(int i);
578 STATIC_SUN void sun_change_sysid(int i, int sys);
579 STATIC_SUN void sun_list_table(int xtra);
580 STATIC_SUN void add_sun_partition(int n, int sys);
581 #if ENABLE_FEATURE_FDISK_ADVANCED
582 STATIC_SUN void sun_set_alt_cyl(void);
583 STATIC_SUN void sun_set_ncyl(int cyl);
584 STATIC_SUN void sun_set_xcyl(void);
585 STATIC_SUN void sun_set_ilfact(void);
586 STATIC_SUN void sun_set_rspeed(void);
587 STATIC_SUN void sun_set_pcylcount(void);
589 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
590 STATIC_SUN void verify_sun(void);
591 STATIC_SUN void sun_write_table(void);
592 #include "fdisk_sun.c"
594 #if ENABLE_FEATURE_FDISK_WRITABLE
595 /* start_sect and nr_sects are stored little endian on all machines */
596 /* moreover, they are not aligned correctly */
598 store4_little_endian(unsigned char *cp, unsigned val)
605 #endif /* FEATURE_FDISK_WRITABLE */
608 read4_little_endian(const unsigned char *cp)
610 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
613 #if ENABLE_FEATURE_FDISK_WRITABLE
615 set_start_sect(struct partition *p, unsigned start_sect)
617 store4_little_endian(p->start4, start_sect);
622 get_start_sect(const struct partition *p)
624 return read4_little_endian(p->start4);
627 #if ENABLE_FEATURE_FDISK_WRITABLE
629 set_nr_sects(struct partition *p, unsigned nr_sects)
631 store4_little_endian(p->size4, nr_sects);
636 get_nr_sects(const struct partition *p)
638 return read4_little_endian(p->size4);
641 /* normally O_RDWR, -l option gives O_RDONLY */
642 static int type_open = O_RDWR;
644 static int ext_index; /* the prime extended partition */
645 static smallint listing; /* no aborts for fdisk -l */
646 static smallint dos_compatible_flag = 1;
647 #if ENABLE_FEATURE_FDISK_WRITABLE
648 //static int dos_changed;
649 static smallint nowarn; /* no warnings for fdisk -l/-s */
652 static unsigned user_cylinders, user_heads, user_sectors;
653 static unsigned pt_heads, pt_sectors;
654 static unsigned kern_heads, kern_sectors;
656 static ullong extended_offset; /* offset of link pointers */
657 static ullong total_number_of_sectors;
659 static void fdisk_fatal(const char *why)
663 longjmp(listingbuf, 1);
665 bb_error_msg_and_die(why, disk_device);
669 seek_sector(ullong secno)
671 secno *= sector_size;
672 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
673 if (lseek64(fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
674 fdisk_fatal(unable_to_seek);
676 if (secno > MAXINT(off_t)
677 || lseek(fd, (off_t)secno, SEEK_SET) == (off_t) -1
679 fdisk_fatal(unable_to_seek);
684 #if ENABLE_FEATURE_FDISK_WRITABLE
686 write_sector(ullong secno, char *buf)
689 if (write(fd, buf, sector_size) != sector_size)
690 fdisk_fatal(unable_to_write);
694 /* Allocate a buffer and read a partition table sector */
696 read_pte(struct pte *pe, ullong offset)
699 pe->sectorbuffer = xmalloc(sector_size);
701 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
702 fdisk_fatal(unable_to_read);
703 #if ENABLE_FEATURE_FDISK_WRITABLE
706 pe->part_table = pe->ext_pointer = NULL;
710 get_partition_start(const struct pte *pe)
712 return pe->offset + get_start_sect(pe->part_table);
715 #if ENABLE_FEATURE_FDISK_WRITABLE
717 * Avoid warning about DOS partitions when no DOS partition was changed.
718 * Here a heuristic "is probably dos partition".
719 * We might also do the opposite and warn in all cases except
720 * for "is probably nondos partition".
724 is_dos_partition(int t)
726 return (t == 1 || t == 4 || t == 6 ||
727 t == 0x0b || t == 0x0c || t == 0x0e ||
728 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
729 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
730 t == 0xc1 || t == 0xc4 || t == 0xc6);
737 puts("Command Action");
739 puts("a\ttoggle a read only flag"); /* sun */
740 puts("b\tedit bsd disklabel");
741 puts("c\ttoggle the mountable flag"); /* sun */
742 puts("d\tdelete a partition");
743 puts("l\tlist known partition types");
744 puts("n\tadd a new partition");
745 puts("o\tcreate a new empty DOS partition table");
746 puts("p\tprint the partition table");
747 puts("q\tquit without saving changes");
748 puts("s\tcreate a new empty Sun disklabel"); /* sun */
749 puts("t\tchange a partition's system id");
750 puts("u\tchange display/entry units");
751 puts("v\tverify the partition table");
752 puts("w\twrite table to disk and exit");
753 #if ENABLE_FEATURE_FDISK_ADVANCED
754 puts("x\textra functionality (experts only)");
756 } else if (LABEL_IS_SGI) {
757 puts("a\tselect bootable partition"); /* sgi flavour */
758 puts("b\tedit bootfile entry"); /* sgi */
759 puts("c\tselect sgi swap partition"); /* sgi flavour */
760 puts("d\tdelete a partition");
761 puts("l\tlist known partition types");
762 puts("n\tadd a new partition");
763 puts("o\tcreate a new empty DOS partition table");
764 puts("p\tprint the partition table");
765 puts("q\tquit without saving changes");
766 puts("s\tcreate a new empty Sun disklabel"); /* sun */
767 puts("t\tchange a partition's system id");
768 puts("u\tchange display/entry units");
769 puts("v\tverify the partition table");
770 puts("w\twrite table to disk and exit");
771 } else if (LABEL_IS_AIX) {
772 puts("o\tcreate a new empty DOS partition table");
773 puts("q\tquit without saving changes");
774 puts("s\tcreate a new empty Sun disklabel"); /* sun */
776 puts("a\ttoggle a bootable flag");
777 puts("b\tedit bsd disklabel");
778 puts("c\ttoggle the dos compatibility flag");
779 puts("d\tdelete a partition");
780 puts("l\tlist known partition types");
781 puts("n\tadd a new partition");
782 puts("o\tcreate a new empty DOS partition table");
783 puts("p\tprint the partition table");
784 puts("q\tquit without saving changes");
785 puts("s\tcreate a new empty Sun disklabel"); /* sun */
786 puts("t\tchange a partition's system id");
787 puts("u\tchange display/entry units");
788 puts("v\tverify the partition table");
789 puts("w\twrite table to disk and exit");
790 #if ENABLE_FEATURE_FDISK_ADVANCED
791 puts("x\textra functionality (experts only)");
795 #endif /* FEATURE_FDISK_WRITABLE */
798 #if ENABLE_FEATURE_FDISK_ADVANCED
802 puts("Command Action");
804 puts("a\tchange number of alternate cylinders"); /*sun*/
805 puts("c\tchange number of cylinders");
806 puts("d\tprint the raw data in the partition table");
807 puts("e\tchange number of extra sectors per cylinder");/*sun*/
808 puts("h\tchange number of heads");
809 puts("i\tchange interleave factor"); /*sun*/
810 puts("o\tchange rotation speed (rpm)"); /*sun*/
811 puts("p\tprint the partition table");
812 puts("q\tquit without saving changes");
813 puts("r\treturn to main menu");
814 puts("s\tchange number of sectors/track");
815 puts("v\tverify the partition table");
816 puts("w\twrite table to disk and exit");
817 puts("y\tchange number of physical cylinders"); /*sun*/
818 } else if (LABEL_IS_SGI) {
819 puts("b\tmove beginning of data in a partition"); /* !sun */
820 puts("c\tchange number of cylinders");
821 puts("d\tprint the raw data in the partition table");
822 puts("e\tlist extended partitions"); /* !sun */
823 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
824 puts("h\tchange number of heads");
825 puts("p\tprint the partition table");
826 puts("q\tquit without saving changes");
827 puts("r\treturn to main menu");
828 puts("s\tchange number of sectors/track");
829 puts("v\tverify the partition table");
830 puts("w\twrite table to disk and exit");
831 } else if (LABEL_IS_AIX) {
832 puts("b\tmove beginning of data in a partition"); /* !sun */
833 puts("c\tchange number of cylinders");
834 puts("d\tprint the raw data in the partition table");
835 puts("e\tlist extended partitions"); /* !sun */
836 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
837 puts("h\tchange number of heads");
838 puts("p\tprint the partition table");
839 puts("q\tquit without saving changes");
840 puts("r\treturn to main menu");
841 puts("s\tchange number of sectors/track");
842 puts("v\tverify the partition table");
843 puts("w\twrite table to disk and exit");
845 puts("b\tmove beginning of data in a partition"); /* !sun */
846 puts("c\tchange number of cylinders");
847 puts("d\tprint the raw data in the partition table");
848 puts("e\tlist extended partitions"); /* !sun */
849 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
850 #if ENABLE_FEATURE_SGI_LABEL
851 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
853 puts("h\tchange number of heads");
854 puts("p\tprint the partition table");
855 puts("q\tquit without saving changes");
856 puts("r\treturn to main menu");
857 puts("s\tchange number of sectors/track");
858 puts("v\tverify the partition table");
859 puts("w\twrite table to disk and exit");
862 #endif /* ADVANCED mode */
864 #if ENABLE_FEATURE_FDISK_WRITABLE
865 static const char *const *
869 LABEL_IS_SUN ? sun_sys_types :
870 LABEL_IS_SGI ? sgi_sys_types :
874 #define get_sys_types() i386_sys_types
875 #endif /* FEATURE_FDISK_WRITABLE */
878 partition_type(unsigned char type)
881 const char *const *types = get_sys_types();
883 for (i = 0; types[i]; i++)
884 if ((unsigned char)types[i][0] == type)
891 #if ENABLE_FEATURE_FDISK_WRITABLE
895 return LABEL_IS_SUN ? sunlabel->infos[i].id :
896 (LABEL_IS_SGI ? sgi_get_sysid(i) :
897 ptes[i].part_table->sys_ind);
901 list_types(const char *const *sys)
906 unsigned done, next, size;
909 for (size = 0; sys[size]; size++) /* */;
912 for (i = COLS-1; i >= 0; i--) {
913 done += (size + i - done) / (i + 1);
914 last[COLS-1 - i] = done;
919 printf("%c%2x %-22.22s", i ? ' ' : '\n',
920 (unsigned char)sys[next][0],
922 next = last[i++] + done;
923 if (i >= COLS || next >= last[i]) {
927 } while (done < last[0]);
930 #endif /* FEATURE_FDISK_WRITABLE */
933 is_cleared_partition(const struct partition *p)
935 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
936 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
937 get_start_sect(p) || get_nr_sects(p));
941 clear_partition(struct partition *p)
945 memset(p, 0, sizeof(struct partition));
948 #if ENABLE_FEATURE_FDISK_WRITABLE
950 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
956 p = ptes[i].ext_pointer;
957 offset = extended_offset;
959 p = ptes[i].part_table;
960 offset = ptes[i].offset;
964 set_start_sect(p, start - offset);
965 set_nr_sects(p, stop - start + 1);
966 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
967 start = g_heads * g_sectors * 1024 - 1;
968 set_hsc(p->head, p->sector, p->cyl, start);
969 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
970 stop = g_heads * g_sectors * 1024 - 1;
971 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
979 if (g_heads && g_sectors && g_cylinders)
982 printf("Unknown value(s) for:");
988 printf(" cylinders");
990 #if ENABLE_FEATURE_FDISK_WRITABLE
991 " (settable in the extra functions menu)"
1000 int cyl_units = g_heads * g_sectors;
1002 if (display_in_cyl_units && cyl_units)
1003 units_per_sector = cyl_units;
1005 units_per_sector = 1; /* in sectors */
1008 #if ENABLE_FEATURE_FDISK_WRITABLE
1010 warn_cylinders(void)
1012 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1014 "The number of cylinders for this disk is set to %d.\n"
1015 "There is nothing wrong with that, but this is larger than 1024,\n"
1016 "and could in certain setups cause problems with:\n"
1017 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1018 "2) booting and partitioning software from other OSs\n"
1019 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1025 read_extended(int ext)
1029 struct partition *p, *q;
1033 pex->ext_pointer = pex->part_table;
1035 p = pex->part_table;
1036 if (!get_start_sect(p)) {
1037 printf("Bad offset in primary extended partition\n");
1041 while (IS_EXTENDED(p->sys_ind)) {
1042 struct pte *pe = &ptes[g_partitions];
1044 if (g_partitions >= MAXIMUM_PARTS) {
1045 /* This is not a Linux restriction, but
1046 this program uses arrays of size MAXIMUM_PARTS.
1047 Do not try to 'improve' this test. */
1048 struct pte *pre = &ptes[g_partitions - 1];
1049 #if ENABLE_FEATURE_FDISK_WRITABLE
1050 printf("Warning: deleting partitions after %d\n",
1054 clear_partition(pre->ext_pointer);
1058 read_pte(pe, extended_offset + get_start_sect(p));
1060 if (!extended_offset)
1061 extended_offset = get_start_sect(p);
1063 q = p = pt_offset(pe->sectorbuffer, 0);
1064 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1065 if (IS_EXTENDED(p->sys_ind)) {
1066 if (pe->ext_pointer)
1067 printf("Warning: extra link "
1068 "pointer in partition table"
1069 " %d\n", g_partitions + 1);
1071 pe->ext_pointer = p;
1072 } else if (p->sys_ind) {
1074 printf("Warning: ignoring extra "
1075 "data in partition table"
1076 " %d\n", g_partitions + 1);
1082 /* very strange code here... */
1083 if (!pe->part_table) {
1084 if (q != pe->ext_pointer)
1087 pe->part_table = q + 1;
1089 if (!pe->ext_pointer) {
1090 if (q != pe->part_table)
1091 pe->ext_pointer = q;
1093 pe->ext_pointer = q + 1;
1096 p = pe->ext_pointer;
1100 #if ENABLE_FEATURE_FDISK_WRITABLE
1101 /* remove empty links */
1103 for (i = 4; i < g_partitions; i++) {
1104 struct pte *pe = &ptes[i];
1106 if (!get_nr_sects(pe->part_table)
1107 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1109 printf("Omitting empty partition (%d)\n", i+1);
1110 delete_partition(i);
1111 goto remove; /* numbering changed */
1117 #if ENABLE_FEATURE_FDISK_WRITABLE
1119 create_doslabel(void)
1123 printf(msg_building_new_label, "DOS disklabel");
1125 current_label_type = label_dos;
1127 #if ENABLE_FEATURE_OSF_LABEL
1128 possibly_osf_label = 0;
1132 for (i = 510-64; i < 510; i++)
1134 write_part_table_flag(MBRbuffer);
1135 extended_offset = 0;
1136 set_all_unchanged();
1138 get_boot(create_empty_dos);
1140 #endif /* FEATURE_FDISK_WRITABLE */
1143 get_sectorsize(void)
1145 if (!user_set_sector_size) {
1147 if (ioctl(fd, BLKSSZGET, &arg) == 0)
1149 if (sector_size != DEFAULT_SECTOR_SIZE)
1150 printf("Note: sector size is %d (not %d)\n",
1151 sector_size, DEFAULT_SECTOR_SIZE);
1156 get_kernel_geometry(void)
1158 struct hd_geometry geometry;
1160 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
1161 kern_heads = geometry.heads;
1162 kern_sectors = geometry.sectors;
1163 /* never use geometry.cylinders - it is truncated */
1168 get_partition_table_geometry(void)
1170 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1171 struct partition *p;
1172 int i, h, s, hh, ss;
1176 if (!(valid_part_table_flag((char*)bufp)))
1180 for (i = 0; i < 4; i++) {
1181 p = pt_offset(bufp, i);
1182 if (p->sys_ind != 0) {
1183 h = p->end_head + 1;
1184 s = (p->end_sector & 077);
1189 } else if (hh != h || ss != s)
1194 if (!first && !bad) {
1206 sec_fac = sector_size / 512;
1207 #if ENABLE_FEATURE_SUN_LABEL
1208 guess_device_type();
1210 g_heads = g_cylinders = g_sectors = 0;
1211 kern_heads = kern_sectors = 0;
1212 pt_heads = pt_sectors = 0;
1214 get_kernel_geometry();
1215 get_partition_table_geometry();
1217 g_heads = user_heads ? user_heads :
1218 pt_heads ? pt_heads :
1219 kern_heads ? kern_heads : 255;
1220 g_sectors = user_sectors ? user_sectors :
1221 pt_sectors ? pt_sectors :
1222 kern_sectors ? kern_sectors : 63;
1223 total_number_of_sectors = bb_BLKGETSIZE_sectors();
1226 if (dos_compatible_flag)
1227 sector_offset = g_sectors;
1229 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1231 g_cylinders = user_cylinders;
1235 * Read MBR. Returns:
1236 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1237 * 0: found or created label
1241 get_boot(enum action what)
1247 for (i = 0; i < 4; i++) {
1248 struct pte *pe = &ptes[i];
1250 pe->part_table = pt_offset(MBRbuffer, i);
1251 pe->ext_pointer = NULL;
1253 pe->sectorbuffer = MBRbuffer;
1254 #if ENABLE_FEATURE_FDISK_WRITABLE
1255 pe->changed = (what == create_empty_dos);
1259 #if ENABLE_FEATURE_SUN_LABEL
1260 if (what == create_empty_sun && check_sun_label())
1264 memset(MBRbuffer, 0, 512);
1266 #if ENABLE_FEATURE_FDISK_WRITABLE
1267 if (what == create_empty_dos)
1268 goto got_dos_table; /* skip reading disk */
1270 fd = open(disk_device, type_open);
1272 fd = open(disk_device, O_RDONLY);
1274 if (what == try_only)
1276 fdisk_fatal(unable_to_open);
1278 printf("You will not be able to write "
1279 "the partition table\n");
1282 if (512 != read(fd, MBRbuffer, 512)) {
1283 if (what == try_only)
1285 fdisk_fatal(unable_to_read);
1288 fd = open(disk_device, O_RDONLY);
1291 if (512 != read(fd, MBRbuffer, 512))
1299 #if ENABLE_FEATURE_SUN_LABEL
1300 if (check_sun_label())
1304 #if ENABLE_FEATURE_SGI_LABEL
1305 if (check_sgi_label())
1309 #if ENABLE_FEATURE_AIX_LABEL
1310 if (check_aix_label())
1314 #if ENABLE_FEATURE_OSF_LABEL
1315 if (check_osf_label()) {
1316 possibly_osf_label = 1;
1317 if (!valid_part_table_flag(MBRbuffer)) {
1318 current_label_type = label_osf;
1321 printf("This disk has both DOS and BSD magic.\n"
1322 "Give the 'b' command to go to BSD mode.\n");
1326 #if ENABLE_FEATURE_FDISK_WRITABLE
1330 if (!valid_part_table_flag(MBRbuffer)) {
1331 #if !ENABLE_FEATURE_FDISK_WRITABLE
1336 printf("Device contains neither a valid DOS "
1337 "partition table, nor Sun, SGI or OSF "
1340 #if ENABLE_FEATURE_SUN_LABEL
1349 case create_empty_dos:
1350 #if ENABLE_FEATURE_SUN_LABEL
1351 case create_empty_sun:
1355 bb_error_msg_and_die("internal error");
1357 #endif /* FEATURE_FDISK_WRITABLE */
1360 #if ENABLE_FEATURE_FDISK_WRITABLE
1365 for (i = 0; i < 4; i++) {
1366 struct pte *pe = &ptes[i];
1368 if (IS_EXTENDED(pe->part_table->sys_ind)) {
1369 if (g_partitions != 4)
1370 printf("Ignoring extra extended "
1371 "partition %d\n", i + 1);
1377 for (i = 3; i < g_partitions; i++) {
1378 struct pte *pe = &ptes[i];
1380 if (!valid_part_table_flag(pe->sectorbuffer)) {
1381 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1382 "table %d will be corrected by w(rite)\n",
1383 pe->sectorbuffer[510],
1384 pe->sectorbuffer[511],
1386 #if ENABLE_FEATURE_FDISK_WRITABLE
1395 #if ENABLE_FEATURE_FDISK_WRITABLE
1397 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1398 * If the user hits Enter, DFLT is returned.
1399 * Answers like +10 are interpreted as offsets from BASE.
1401 * There is no default if DFLT is not between LOW and HIGH.
1404 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1408 const char *fmt = "%s (%u-%u, default %u): ";
1410 if (dflt < low || dflt > high) {
1411 fmt = "%s (%u-%u): ";
1416 int use_default = default_ok;
1418 /* ask question and read answer */
1420 printf(fmt, mesg, low, high, dflt);
1421 read_maybe_empty("");
1422 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1423 && *line_ptr != '-' && *line_ptr != '+');
1425 if (*line_ptr == '+' || *line_ptr == '-') {
1426 int minus = (*line_ptr == '-');
1429 i = atoi(line_ptr + 1);
1431 while (isdigit(*++line_ptr))
1434 switch (*line_ptr) {
1437 if (!display_in_cyl_units)
1438 i *= g_heads * g_sectors;
1452 absolute = 1000000000;
1461 bytes = (ullong) i * absolute;
1462 unit = sector_size * units_per_sector;
1463 bytes += unit/2; /* round */
1472 while (isdigit(*line_ptr)) {
1479 printf("Using default value %u\n", i);
1481 if (i >= low && i <= high)
1483 printf("Value is out of range\n");
1489 get_partition(int warn, int max)
1494 i = read_int(1, 0, max, 0, "Partition number") - 1;
1498 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1499 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1500 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1502 printf("Warning: partition %d has empty type\n", i+1);
1509 get_existing_partition(int warn, int max)
1514 for (i = 0; i < max; i++) {
1515 struct pte *pe = &ptes[i];
1516 struct partition *p = pe->part_table;
1518 if (p && !is_cleared_partition(p)) {
1525 printf("Selected partition %d\n", pno+1);
1528 printf("No partition is defined yet!\n");
1532 return get_partition(warn, max);
1536 get_nonexisting_partition(int warn, int max)
1541 for (i = 0; i < max; i++) {
1542 struct pte *pe = &ptes[i];
1543 struct partition *p = pe->part_table;
1545 if (p && is_cleared_partition(p)) {
1552 printf("Selected partition %d\n", pno+1);
1555 printf("All primary partitions have been defined already!\n");
1559 return get_partition(warn, max);
1566 display_in_cyl_units = !display_in_cyl_units;
1568 printf("Changing display/entry units to %s\n",
1573 toggle_active(int i)
1575 struct pte *pe = &ptes[i];
1576 struct partition *p = pe->part_table;
1578 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1579 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1580 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1585 toggle_dos_compatibility_flag(void)
1587 dos_compatible_flag = 1 - dos_compatible_flag;
1588 if (dos_compatible_flag) {
1589 sector_offset = g_sectors;
1590 printf("DOS Compatibility flag is set\n");
1593 printf("DOS Compatibility flag is not set\n");
1598 delete_partition(int i)
1600 struct pte *pe = &ptes[i];
1601 struct partition *p = pe->part_table;
1602 struct partition *q = pe->ext_pointer;
1604 /* Note that for the fifth partition (i == 4) we don't actually
1605 * decrement partitions.
1608 if (warn_geometry())
1609 return; /* C/H/S not set */
1613 sun_delete_partition(i);
1617 sgi_delete_partition(i);
1622 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1624 ptes[ext_index].ext_pointer = NULL;
1625 extended_offset = 0;
1631 if (!q->sys_ind && i > 4) {
1632 /* the last one in the chain - just delete */
1635 clear_partition(ptes[i].ext_pointer);
1636 ptes[i].changed = 1;
1638 /* not the last one - further ones will be moved down */
1640 /* delete this link in the chain */
1641 p = ptes[i-1].ext_pointer;
1643 set_start_sect(p, get_start_sect(q));
1644 set_nr_sects(p, get_nr_sects(q));
1645 ptes[i-1].changed = 1;
1646 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1647 /* the first logical in a longer chain */
1650 if (pe->part_table) /* prevent SEGFAULT */
1651 set_start_sect(pe->part_table,
1652 get_partition_start(pe) -
1654 pe->offset = extended_offset;
1658 if (g_partitions > 5) {
1660 while (i < g_partitions) {
1661 ptes[i] = ptes[i+1];
1665 /* the only logical: clear only */
1666 clear_partition(ptes[i].part_table);
1673 int i, sys, origsys;
1674 struct partition *p;
1676 /* If sgi_label then don't use get_existing_partition,
1677 let the user select a partition, since get_existing_partition()
1678 only works for Linux like partition tables. */
1679 if (!LABEL_IS_SGI) {
1680 i = get_existing_partition(0, g_partitions);
1682 i = get_partition(0, g_partitions);
1686 p = ptes[i].part_table;
1687 origsys = sys = get_sysid(i);
1689 /* if changing types T to 0 is allowed, then
1690 the reverse change must be allowed, too */
1691 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1692 printf("Partition %d does not exist yet!\n", i + 1);
1696 sys = read_hex(get_sys_types());
1698 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1699 printf("Type 0 means free space to many systems\n"
1700 "(but not to Linux). Having partitions of\n"
1701 "type 0 is probably unwise.\n");
1705 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1706 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1707 printf("You cannot change a partition into"
1708 " an extended one or vice versa\n");
1714 #if ENABLE_FEATURE_SUN_LABEL
1715 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1716 printf("Consider leaving partition 3 "
1717 "as Whole disk (5),\n"
1718 "as SunOS/Solaris expects it and "
1719 "even Linux likes it\n\n");
1721 #if ENABLE_FEATURE_SGI_LABEL
1724 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1725 (i == 8 && sys != 0)
1728 printf("Consider leaving partition 9 "
1729 "as volume header (0),\nand "
1730 "partition 11 as entire volume (6)"
1731 "as IRIX expects it\n\n");
1737 sun_change_sysid(i, sys);
1738 } else if (LABEL_IS_SGI) {
1739 sgi_change_sysid(i, sys);
1743 printf("Changed system type of partition %d "
1744 "to %x (%s)\n", i + 1, sys,
1745 partition_type(sys));
1746 ptes[i].changed = 1;
1747 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1753 #endif /* FEATURE_FDISK_WRITABLE */
1756 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1757 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1758 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1759 * Lubkin Oct. 1991). */
1762 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1764 int spc = g_heads * g_sectors;
1768 *h = ls / g_sectors;
1769 *s = ls % g_sectors + 1; /* sectors count from 1 */
1773 check_consistency(const struct partition *p, int partition)
1775 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1776 unsigned pec, peh, pes; /* physical ending c, h, s */
1777 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1778 unsigned lec, leh, les; /* logical ending c, h, s */
1780 if (!g_heads || !g_sectors || (partition >= 4))
1781 return; /* do not check extended partitions */
1783 /* physical beginning c, h, s */
1784 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1786 pbs = p->sector & 0x3f;
1788 /* physical ending c, h, s */
1789 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1791 pes = p->end_sector & 0x3f;
1793 /* compute logical beginning (c, h, s) */
1794 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1796 /* compute logical ending (c, h, s) */
1797 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1799 /* Same physical / logical beginning? */
1800 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1801 printf("Partition %d has different physical/logical "
1802 "beginnings (non-Linux?):\n", partition + 1);
1803 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1804 printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
1807 /* Same physical / logical ending? */
1808 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1809 printf("Partition %d has different physical/logical "
1810 "endings:\n", partition + 1);
1811 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1812 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1815 /* Ending on cylinder boundary? */
1816 if (peh != (g_heads - 1) || pes != g_sectors) {
1817 printf("Partition %i does not end on cylinder boundary\n",
1823 list_disk_geometry(void)
1825 long long bytes = (total_number_of_sectors << 9);
1826 long megabytes = bytes/1000000;
1828 if (megabytes < 10000)
1829 printf("\nDisk %s: %ld MB, %lld bytes\n",
1830 disk_device, megabytes, bytes);
1832 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1833 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1834 printf("%d heads, %d sectors/track, %d cylinders",
1835 g_heads, g_sectors, g_cylinders);
1836 if (units_per_sector == 1)
1837 printf(", total %llu sectors",
1838 total_number_of_sectors / (sector_size/512));
1839 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1841 units_per_sector, sector_size, units_per_sector * sector_size);
1845 * Check whether partition entries are ordered by their starting positions.
1846 * Return 0 if OK. Return i if partition i should have been earlier.
1847 * Two separate checks: primary and logical partitions.
1850 wrong_p_order(int *prev)
1852 const struct pte *pe;
1853 const struct partition *p;
1854 ullong last_p_start_pos = 0, p_start_pos;
1857 for (i = 0; i < g_partitions; i++) {
1860 last_p_start_pos = 0;
1865 p_start_pos = get_partition_start(pe);
1867 if (last_p_start_pos > p_start_pos) {
1873 last_p_start_pos = p_start_pos;
1880 #if ENABLE_FEATURE_FDISK_ADVANCED
1882 * Fix the chain of logicals.
1883 * extended_offset is unchanged, the set of sectors used is unchanged
1884 * The chain is sorted so that sectors increase, and so that
1885 * starting sectors increase.
1887 * After this it may still be that cfdisk doesnt like the table.
1888 * (This is because cfdisk considers expanded parts, from link to
1889 * end of partition, and these may still overlap.)
1891 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1895 fix_chain_of_logicals(void)
1897 int j, oj, ojj, sj, sjj;
1898 struct partition *pj,*pjj,tmp;
1900 /* Stage 1: sort sectors but leave sector of part 4 */
1901 /* (Its sector is the global extended_offset.) */
1903 for (j = 5; j < g_partitions - 1; j++) {
1904 oj = ptes[j].offset;
1905 ojj = ptes[j+1].offset;
1907 ptes[j].offset = ojj;
1908 ptes[j+1].offset = oj;
1909 pj = ptes[j].part_table;
1910 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1911 pjj = ptes[j+1].part_table;
1912 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1913 set_start_sect(ptes[j-1].ext_pointer,
1914 ojj-extended_offset);
1915 set_start_sect(ptes[j].ext_pointer,
1916 oj-extended_offset);
1921 /* Stage 2: sort starting sectors */
1923 for (j = 4; j < g_partitions - 1; j++) {
1924 pj = ptes[j].part_table;
1925 pjj = ptes[j+1].part_table;
1926 sj = get_start_sect(pj);
1927 sjj = get_start_sect(pjj);
1928 oj = ptes[j].offset;
1929 ojj = ptes[j+1].offset;
1930 if (oj+sj > ojj+sjj) {
1934 set_start_sect(pj, ojj+sjj-oj);
1935 set_start_sect(pjj, oj+sj-ojj);
1940 /* Probably something was changed */
1941 for (j = 4; j < g_partitions; j++)
1942 ptes[j].changed = 1;
1947 fix_partition_table_order(void)
1949 struct pte *pei, *pek;
1952 if (!wrong_p_order(NULL)) {
1953 printf("Ordering is already correct\n\n");
1957 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1958 /* partition i should have come earlier, move it */
1959 /* We have to move data in the MBR */
1960 struct partition *pi, *pk, *pe, pbuf;
1964 pe = pei->ext_pointer;
1965 pei->ext_pointer = pek->ext_pointer;
1966 pek->ext_pointer = pe;
1968 pi = pei->part_table;
1969 pk = pek->part_table;
1971 memmove(&pbuf, pi, sizeof(struct partition));
1972 memmove(pi, pk, sizeof(struct partition));
1973 memmove(pk, &pbuf, sizeof(struct partition));
1975 pei->changed = pek->changed = 1;
1979 fix_chain_of_logicals();
1987 list_table(int xtra)
1989 const struct partition *p;
1993 sun_list_table(xtra);
1997 sgi_list_table(xtra);
2001 list_disk_geometry();
2004 xbsd_print_disklabel(xtra);
2008 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2009 but if the device name ends in a digit, say /dev/foo1,
2010 then the partition is called /dev/foo1p3. */
2011 w = strlen(disk_device);
2012 if (w && isdigit(disk_device[w-1]))
2017 // 1 12345678901 12345678901 12345678901 12
2018 printf("%*s Boot Start End Blocks Id System\n",
2021 for (i = 0; i < g_partitions; i++) {
2022 const struct pte *pe = &ptes[i];
2028 if (!p || is_cleared_partition(p))
2031 psects = get_nr_sects(p);
2035 if (sector_size < 1024) {
2036 pblocks /= (1024 / sector_size);
2037 podd = psects % (1024 / sector_size);
2039 if (sector_size > 1024)
2040 pblocks *= (sector_size / 1024);
2042 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2043 partname(disk_device, i+1, w+2),
2044 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2046 (ullong) cround(get_partition_start(pe)), /* start */
2047 (ullong) cround(get_partition_start(pe) + psects /* end */
2048 - (psects ? 1 : 0)),
2049 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2050 p->sys_ind, /* type id */
2051 partition_type(p->sys_ind)); /* type name */
2053 check_consistency(p, i);
2056 /* Is partition table in disk order? It need not be, but... */
2057 /* partition table entries are not checked for correct order if this
2058 is a sgi, sun or aix labeled disk... */
2059 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2061 printf("\nPartition table entries are not in disk order\n");
2065 #if ENABLE_FEATURE_FDISK_ADVANCED
2067 x_list_table(int extend)
2069 const struct pte *pe;
2070 const struct partition *p;
2073 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2074 disk_device, g_heads, g_sectors, g_cylinders);
2075 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2076 for (i = 0; i < g_partitions; i++) {
2078 p = (extend ? pe->ext_pointer : pe->part_table);
2080 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2081 i + 1, p->boot_ind, p->head,
2083 cylinder(p->sector, p->cyl), p->end_head,
2084 sector(p->end_sector),
2085 cylinder(p->end_sector, p->end_cyl),
2086 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2088 check_consistency(p, i);
2094 #if ENABLE_FEATURE_FDISK_WRITABLE
2096 fill_bounds(ullong *first, ullong *last)
2099 const struct pte *pe = &ptes[0];
2100 const struct partition *p;
2102 for (i = 0; i < g_partitions; pe++,i++) {
2104 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2105 first[i] = 0xffffffff;
2108 first[i] = get_partition_start(pe);
2109 last[i] = first[i] + get_nr_sects(p) - 1;
2115 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2117 ullong total, real_s, real_c;
2119 real_s = sector(s) - 1;
2120 real_c = cylinder(s, c);
2121 total = (real_c * g_sectors + real_s) * g_heads + h;
2123 printf("Partition %d contains sector 0\n", n);
2125 printf("Partition %d: head %d greater than maximum %d\n",
2127 if (real_s >= g_sectors)
2128 printf("Partition %d: sector %d greater than "
2129 "maximum %d\n", n, s, g_sectors);
2130 if (real_c >= g_cylinders)
2131 printf("Partition %d: cylinder %llu greater than "
2132 "maximum %d\n", n, real_c + 1, g_cylinders);
2133 if (g_cylinders <= 1024 && start != total)
2134 printf("Partition %d: previous sectors %llu disagrees with "
2135 "total %llu\n", n, start, total);
2143 ullong first[g_partitions], last[g_partitions];
2144 struct partition *p;
2146 if (warn_geometry())
2158 fill_bounds(first, last);
2159 for (i = 0; i < g_partitions; i++) {
2160 struct pte *pe = &ptes[i];
2163 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2164 check_consistency(p, i);
2165 if (get_partition_start(pe) < first[i])
2166 printf("Warning: bad start-of-data in "
2167 "partition %d\n", i + 1);
2168 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2170 total += last[i] + 1 - first[i];
2171 for (j = 0; j < i; j++) {
2172 if ((first[i] >= first[j] && first[i] <= last[j])
2173 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2174 printf("Warning: partition %d overlaps "
2175 "partition %d\n", j + 1, i + 1);
2176 total += first[i] >= first[j] ?
2177 first[i] : first[j];
2178 total -= last[i] <= last[j] ?
2185 if (extended_offset) {
2186 struct pte *pex = &ptes[ext_index];
2187 ullong e_last = get_start_sect(pex->part_table) +
2188 get_nr_sects(pex->part_table) - 1;
2190 for (i = 4; i < g_partitions; i++) {
2192 p = ptes[i].part_table;
2194 if (i != 4 || i + 1 < g_partitions)
2195 printf("Warning: partition %d "
2196 "is empty\n", i + 1);
2197 } else if (first[i] < extended_offset || last[i] > e_last) {
2198 printf("Logical partition %d not entirely in "
2199 "partition %d\n", i + 1, ext_index + 1);
2204 if (total > g_heads * g_sectors * g_cylinders)
2205 printf("Total allocated sectors %d greater than the maximum "
2206 "%d\n", total, g_heads * g_sectors * g_cylinders);
2208 total = g_heads * g_sectors * g_cylinders - total;
2210 printf("%d unallocated sectors\n", total);
2215 add_partition(int n, int sys)
2217 char mesg[256]; /* 48 does not suffice in Japanese */
2218 int i, num_read = 0;
2219 struct partition *p = ptes[n].part_table;
2220 struct partition *q = ptes[ext_index].part_table;
2222 ullong start, stop = 0;
2223 ullong first[g_partitions], last[g_partitions];
2225 if (p && p->sys_ind) {
2226 printf(msg_part_already_defined, n + 1);
2229 fill_bounds(first, last);
2231 start = sector_offset;
2232 if (display_in_cyl_units || !total_number_of_sectors)
2233 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2235 limit = total_number_of_sectors - 1;
2236 if (extended_offset) {
2237 first[ext_index] = extended_offset;
2238 last[ext_index] = get_start_sect(q) +
2239 get_nr_sects(q) - 1;
2242 start = extended_offset + sector_offset;
2243 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2245 if (display_in_cyl_units)
2246 for (i = 0; i < g_partitions; i++)
2247 first[i] = (cround(first[i]) - 1) * units_per_sector;
2249 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2252 for (i = 0; i < g_partitions; i++) {
2255 if (start == ptes[i].offset)
2256 start += sector_offset;
2257 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2258 if (start >= first[i] && start <= lastplusoff)
2259 start = lastplusoff + 1;
2263 if (start >= temp+units_per_sector && num_read) {
2264 printf("Sector %lld is already allocated\n", temp);
2268 if (!num_read && start == temp) {
2271 saved_start = start;
2272 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2274 if (display_in_cyl_units) {
2275 start = (start - 1) * units_per_sector;
2276 if (start < saved_start) start = saved_start;
2280 } while (start != temp || !num_read);
2281 if (n > 4) { /* NOT for fifth partition */
2282 struct pte *pe = &ptes[n];
2284 pe->offset = start - sector_offset;
2285 if (pe->offset == extended_offset) { /* must be corrected */
2287 if (sector_offset == 1)
2292 for (i = 0; i < g_partitions; i++) {
2293 struct pte *pe = &ptes[i];
2295 if (start < pe->offset && limit >= pe->offset)
2296 limit = pe->offset - 1;
2297 if (start < first[i] && limit >= first[i])
2298 limit = first[i] - 1;
2300 if (start > limit) {
2301 printf("No free sectors available\n");
2306 if (cround(start) == cround(limit)) {
2309 snprintf(mesg, sizeof(mesg),
2310 "Last %s or +size or +sizeM or +sizeK",
2311 str_units(SINGULAR));
2312 stop = read_int(cround(start), cround(limit), cround(limit),
2313 cround(start), mesg);
2314 if (display_in_cyl_units) {
2315 stop = stop * units_per_sector - 1;
2321 set_partition(n, 0, start, stop, sys);
2323 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2325 if (IS_EXTENDED(sys)) {
2326 struct pte *pe4 = &ptes[4];
2327 struct pte *pen = &ptes[n];
2330 pen->ext_pointer = p;
2331 pe4->offset = extended_offset = start;
2332 pe4->sectorbuffer = xzalloc(sector_size);
2333 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2334 pe4->ext_pointer = pe4->part_table + 1;
2343 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2344 struct pte *pe = &ptes[g_partitions];
2346 pe->sectorbuffer = xzalloc(sector_size);
2347 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2348 pe->ext_pointer = pe->part_table + 1;
2353 add_partition(g_partitions - 1, LINUX_NATIVE);
2359 int i, free_primary = 0;
2361 if (warn_geometry())
2365 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2369 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2373 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2374 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2375 "table first (use 'o'). This will destroy the present disk contents.\n");
2379 for (i = 0; i < 4; i++)
2380 free_primary += !ptes[i].part_table->sys_ind;
2382 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2383 printf("The maximum number of partitions has been created\n");
2387 if (!free_primary) {
2388 if (extended_offset)
2391 printf("You must delete some partition and add "
2392 "an extended partition first\n");
2395 snprintf(line, sizeof(line),
2398 " p primary partition (1-4)\n",
2400 "l logical (5 or over)" : "e extended"));
2402 c = read_nonempty(line);
2403 if (c == 'p' || c == 'P') {
2404 i = get_nonexisting_partition(0, 4);
2406 add_partition(i, LINUX_NATIVE);
2409 if (c == 'l' && extended_offset) {
2413 if (c == 'e' && !extended_offset) {
2414 i = get_nonexisting_partition(0, 4);
2416 add_partition(i, EXTENDED);
2419 printf("Invalid partition number "
2420 "for type '%c'\n", c);
2431 for (i = 0; i < 3; i++)
2432 if (ptes[i].changed)
2433 ptes[3].changed = 1;
2434 for (i = 3; i < g_partitions; i++) {
2435 struct pte *pe = &ptes[i];
2438 write_part_table_flag(pe->sectorbuffer);
2439 write_sector(pe->offset, pe->sectorbuffer);
2443 else if (LABEL_IS_SGI) {
2444 /* no test on change? the printf below might be mistaken */
2447 else if (LABEL_IS_SUN) {
2450 for (i = 0; i < 8; i++)
2451 if (ptes[i].changed)
2457 printf("The partition table has been altered!\n\n");
2458 reread_partition_table(1);
2462 reread_partition_table(int leave)
2466 printf("Calling ioctl() to re-read partition table\n");
2468 /* sleep(2); Huh? */
2469 i = ioctl_or_perror(fd, BLKRRPART, NULL,
2470 "WARNING: rereading partition table "
2471 "failed, kernel still uses old table");
2475 "\nWARNING: If you have created or modified any DOS 6.x\n"
2476 "partitions, please see the fdisk manual page for additional\n"
2481 if (ENABLE_FEATURE_CLEAN_UP)
2486 #endif /* FEATURE_FDISK_WRITABLE */
2488 #if ENABLE_FEATURE_FDISK_ADVANCED
2489 #define MAX_PER_LINE 16
2491 print_buffer(char *pbuffer)
2495 for (i = 0, l = 0; i < sector_size; i++, l++) {
2497 printf("0x%03X:", i);
2498 printf(" %02X", (unsigned char) pbuffer[i]);
2499 if (l == MAX_PER_LINE - 1) {
2514 printf("Device: %s\n", disk_device);
2515 if (LABEL_IS_SGI || LABEL_IS_SUN)
2516 print_buffer(MBRbuffer);
2518 for (i = 3; i < g_partitions; i++)
2519 print_buffer(ptes[i].sectorbuffer);
2526 struct pte *pe = &ptes[i];
2527 struct partition *p = pe->part_table;
2530 if (warn_geometry())
2532 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2533 printf("Partition %d has no data area\n", i + 1);
2536 first = get_partition_start(pe);
2537 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2538 "New beginning of data") - pe->offset;
2540 if (new != get_nr_sects(p)) {
2541 first = get_nr_sects(p) + get_start_sect(p) - new;
2542 set_nr_sects(p, first);
2543 set_start_sect(p, new);
2555 c = tolower(read_nonempty("Expert command (m for help): "));
2563 move_begin(get_partition(0, g_partitions));
2566 user_cylinders = g_cylinders =
2567 read_int(1, g_cylinders, 1048576, 0,
2568 "Number of cylinders");
2570 sun_set_ncyl(g_cylinders);
2580 else if (LABEL_IS_SUN)
2582 else if (LABEL_IS_DOS)
2587 fix_partition_table_order();
2590 #if ENABLE_FEATURE_SGI_LABEL
2595 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2620 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2621 "Number of sectors");
2622 if (dos_compatible_flag) {
2623 sector_offset = g_sectors;
2624 printf("Warning: setting sector offset for DOS "
2633 write_table(); /* does not return */
2637 sun_set_pcylcount();
2644 #endif /* ADVANCED mode */
2647 is_ide_cdrom_or_tape(const char *device)
2651 struct stat statbuf;
2654 /* No device was given explicitly, and we are trying some
2655 likely things. But opening /dev/hdc may produce errors like
2656 "hdc: tray open or drive not ready"
2657 if it happens to be a CD-ROM drive. It even happens that
2658 the process hangs on the attempt to read a music CD.
2659 So try to be careful. This only works since 2.1.73. */
2661 if (strncmp("/dev/hd", device, 7))
2664 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2665 procf = fopen(buf, "r");
2666 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2667 is_ide = (!strncmp(buf, "cdrom", 5) ||
2668 !strncmp(buf, "tape", 4));
2670 /* Now when this proc file does not exist, skip the
2671 device when it is read-only. */
2672 if (stat(device, &statbuf) == 0)
2673 is_ide = ((statbuf.st_mode & 0222) == 0);
2682 trydev(const char *device, int user_specified)
2686 disk_device = device;
2687 if (setjmp(listingbuf))
2689 if (!user_specified)
2690 if (is_ide_cdrom_or_tape(device))
2692 fd = open(disk_device, type_open);
2694 gb = get_boot(try_only);
2695 if (gb > 0) { /* I/O error */
2697 } else if (gb < 0) { /* no DOS signature */
2698 list_disk_geometry();
2702 #if ENABLE_FEATURE_OSF_LABEL
2703 if (bsd_trydev(device) < 0)
2705 printf("Disk %s doesn't contain a valid "
2706 "partition table\n", device);
2711 #if ENABLE_FEATURE_FDISK_WRITABLE
2712 if (!LABEL_IS_SUN && g_partitions > 4){
2713 delete_partition(ext_index);
2718 /* Ignore other errors, since we try IDE
2719 and SCSI hard disks which may not be
2720 installed on the system. */
2721 if (errno == EACCES) {
2722 printf("Cannot open %s\n", device);
2728 /* for fdisk -l: try all things in /proc/partitions
2729 that look like a partition name (do not end in a digit) */
2734 char line[100], ptname[100], devname[120], *s;
2737 procpt = fopen_or_warn("/proc/partitions", "r");
2739 while (fgets(line, sizeof(line), procpt)) {
2740 if (sscanf(line, " %d %d %d %[^\n ]",
2741 &ma, &mi, &sz, ptname) != 4)
2743 for (s = ptname; *s; s++)
2747 sprintf(devname, "/dev/%s", ptname);
2750 #if ENABLE_FEATURE_CLEAN_UP
2755 #if ENABLE_FEATURE_FDISK_WRITABLE
2757 unknown_command(int c)
2759 printf("%c: unknown command\n", c);
2763 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2764 int fdisk_main(int argc, char **argv)
2769 * fdisk -l [-b sectorsize] [-u] device ...
2770 * fdisk -s [partition] ...
2771 * fdisk [-b sectorsize] [-u] device
2773 * Options -C, -H, -S set the geometry.
2782 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
2787 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2788 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2789 §or_size, &user_cylinders, &user_heads, &user_sectors);
2792 if (opt & OPT_b) { // -b
2793 /* Ugly: this sector size is really per device,
2794 so cannot be combined with multiple disks,
2795 and the same goes for the C/H/S options.
2797 if (sector_size != 512 && sector_size != 1024
2798 && sector_size != 2048)
2801 user_set_sector_size = 1;
2803 if (user_heads <= 0 || user_heads >= 256)
2805 if (user_sectors <= 0 || user_sectors >= 64)
2808 display_in_cyl_units = 0; // -u
2810 #if ENABLE_FEATURE_FDISK_WRITABLE
2814 type_open = O_RDONLY;
2821 /* we don't have device names, */
2822 /* use /proc/partitions instead */
2826 #if ENABLE_FEATURE_FDISK_WRITABLE
2830 #if ENABLE_FEATURE_FDISK_BLKSIZE
2837 for (j = 0; j < argc; j++) {
2838 unsigned long long size;
2839 fd = xopen(argv[j], O_RDONLY);
2840 size = bb_BLKGETSIZE_sectors() / 2;
2843 printf("%lld\n", size);
2845 printf("%s: %lld\n", argv[j], size);
2851 #if ENABLE_FEATURE_FDISK_WRITABLE
2855 disk_device = argv[0];
2859 /* OSF label, and no DOS label */
2860 printf("Detected an OSF/1 disklabel on %s, entering "
2861 "disklabel mode\n", disk_device);
2863 /*Why do we do this? It seems to be counter-intuitive*/
2864 current_label_type = label_dos;
2865 /* If we return we may want to make an empty DOS label? */
2871 c = tolower(read_nonempty("Command (m for help): "));
2875 toggle_active(get_partition(1, g_partitions));
2876 else if (LABEL_IS_SUN)
2877 toggle_sunflags(get_partition(1, g_partitions),
2879 else if (LABEL_IS_SGI)
2880 sgi_set_bootpartition(
2881 get_partition(1, g_partitions));
2887 printf("\nThe current boot file is: %s\n",
2888 sgi_get_bootfile());
2889 if (read_maybe_empty("Please enter the name of the "
2890 "new boot file: ") == '\n')
2891 printf("Boot file unchanged\n");
2893 sgi_set_bootfile(line_ptr);
2895 #if ENABLE_FEATURE_OSF_LABEL
2902 toggle_dos_compatibility_flag();
2903 else if (LABEL_IS_SUN)
2904 toggle_sunflags(get_partition(1, g_partitions),
2906 else if (LABEL_IS_SGI)
2907 sgi_set_swappartition(
2908 get_partition(1, g_partitions));
2915 /* If sgi_label then don't use get_existing_partition,
2916 let the user select a partition, since
2917 get_existing_partition() only works for Linux-like
2919 if (!LABEL_IS_SGI) {
2920 j = get_existing_partition(1, g_partitions);
2922 j = get_partition(1, g_partitions);
2925 delete_partition(j);
2934 list_types(get_sys_types());
2953 #if ENABLE_FEATURE_SUN_LABEL
2967 write_table(); /* does not return */
2969 #if ENABLE_FEATURE_FDISK_ADVANCED
2972 printf("\n\tSorry, no experts menu for SGI "
2973 "partition tables available\n\n");
2984 #endif /* FEATURE_FDISK_WRITABLE */