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 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
132 static int get_boot(enum action what);
134 static int get_boot(void);
140 static unsigned get_start_sect(const struct partition *p);
141 static unsigned get_nr_sects(const struct partition *p);
144 * per partition table entry data
146 * The four primary partitions have the same sectorbuffer (MBRbuffer)
147 * and have NULL ext_pointer.
148 * Each logical partition table entry has two pointers, one for the
149 * partition and one link to the next one.
152 struct partition *part_table; /* points into sectorbuffer */
153 struct partition *ext_pointer; /* points into sectorbuffer */
154 ullong offset; /* disk sector number */
155 char *sectorbuffer; /* disk sector contents */
156 #if ENABLE_FEATURE_FDISK_WRITABLE
157 char changed; /* boolean */
161 /* DOS partition types */
163 static const char *const i386_sys_types[] = {
167 "\x05" "Extended", /* DOS 3.3+ extended partition */
168 "\x06" "FAT16", /* DOS 16-bit >=32M */
169 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
170 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
171 "\x0b" "Win95 FAT32",
172 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
173 "\x0e" "Win95 FAT16 (LBA)",
174 "\x0f" "Win95 Ext'd (LBA)",
175 "\x11" "Hidden FAT12",
176 "\x12" "Compaq diagnostics",
177 "\x14" "Hidden FAT16 <32M",
178 "\x16" "Hidden FAT16",
179 "\x17" "Hidden HPFS/NTFS",
180 "\x1b" "Hidden Win95 FAT32",
181 "\x1c" "Hidden W95 FAT32 (LBA)",
182 "\x1e" "Hidden W95 FAT16 (LBA)",
183 "\x3c" "Part.Magic recovery",
184 "\x41" "PPC PReP Boot",
186 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
187 "\x80" "Old Minix", /* Minix 1.4a and earlier */
188 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
189 "\x82" "Linux swap", /* also Solaris */
191 "\x84" "OS/2 hidden C: drive",
192 "\x85" "Linux extended",
193 "\x86" "NTFS volume set",
194 "\x87" "NTFS volume set",
196 "\x9f" "BSD/OS", /* BSDI */
197 "\xa0" "Thinkpad hibernation",
198 "\xa5" "FreeBSD", /* various BSD flavours */
202 "\xab" "Darwin boot",
205 "\xbe" "Solaris boot",
207 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
208 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
209 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
210 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
211 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
212 autodetect using persistent
214 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
217 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
218 "\x09" "AIX bootable", /* AIX data or Coherent */
220 "\x18" "AST SmartSleep",
223 "\x40" "Venix 80286",
225 "\x4e" "QNX4.x 2nd part",
226 "\x4f" "QNX4.x 3rd part",
228 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
229 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
230 "\x53" "OnTrack DM6 Aux3",
234 "\x5c" "Priam Edisk",
236 "\x64" "Novell Netware 286",
237 "\x65" "Novell Netware 386",
238 "\x70" "DiskSecure Multi-Boot",
241 "\x94" "Amoeba BBT", /* (bad block table) */
243 "\xbb" "Boot Wizard hidden",
244 "\xc1" "DRDOS/sec (FAT-12)",
245 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
246 "\xc6" "DRDOS/sec (FAT-16)",
248 "\xda" "Non-FS data",
249 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
250 Concurrent DOS or CTOS */
251 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
252 "\xdf" "BootIt", /* BootIt EMBRM */
253 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
254 extended partition */
255 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
256 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
257 partition < 1024 cyl. */
259 "\xf4" "SpeedStor", /* SpeedStor large partition */
260 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
261 "\xff" "BBT", /* Xenix Bad Block Table */
272 const char *disk_device;
273 int fd; /* the disk */
274 int g_partitions; // = 4; /* maximum partition + 1 */
275 unsigned units_per_sector; // = 1;
276 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
277 unsigned user_set_sector_size;
278 unsigned sector_offset; // = 1;
279 unsigned g_heads, g_sectors, g_cylinders;
280 enum label_type current_label_type;
281 smallint display_in_cyl_units; // = 1;
282 #if ENABLE_FEATURE_OSF_LABEL
283 smallint possibly_osf_label;
287 char line_buffer[80];
288 char partname_buffer[80];
289 /* Raw disk label. For DOS-type partition tables the MBR,
290 * with descriptions of the primary partitions. */
291 char MBRbuffer[MAX_SECTOR_SIZE];
292 /* Partition tables */
293 struct pte ptes[MAXIMUM_PARTS];
295 #define G (*ptr_to_globals)
296 #define line_ptr (G.line_ptr)
297 #define disk_device (G.disk_device )
299 #define g_partitions (G.g_partitions )
300 #define units_per_sector (G.units_per_sector )
301 #define sector_size (G.sector_size )
302 #define user_set_sector_size (G.user_set_sector_size)
303 #define sector_offset (G.sector_offset )
304 #define g_heads (G.g_heads )
305 #define g_sectors (G.g_sectors )
306 #define g_cylinders (G.g_cylinders )
307 #define current_label_type (G.current_label_type )
308 #define display_in_cyl_units (G.display_in_cyl_units)
309 #define possibly_osf_label (G.possibly_osf_label )
310 #define listingbuf (G.listingbuf)
311 #define line_buffer (G.line_buffer)
312 #define partname_buffer (G.partname_buffer)
313 #define MBRbuffer (G.MBRbuffer)
314 #define ptes (G.ptes)
315 #define INIT_G() do { \
316 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
317 sector_size = DEFAULT_SECTOR_SIZE; \
320 display_in_cyl_units = 1; \
321 units_per_sector = 1; \
325 /* TODO: move to libbb? */
326 static ullong bb_BLKGETSIZE_sectors(void)
329 unsigned long longsectors;
331 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
332 /* got bytes, convert to 512 byte sectors */
335 /* Needs temp of type long */
336 if (ioctl(fd, BLKGETSIZE, &longsectors))
342 #define IS_EXTENDED(i) \
343 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
345 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
347 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
349 #define pt_offset(b, n) \
350 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
352 #define sector(s) ((s) & 0x3f)
354 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
356 #define hsc2sector(h,s,c) \
357 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
359 #define set_hsc(h,s,c,sector) \
361 s = sector % g_sectors + 1; \
362 sector /= g_sectors; \
363 h = sector % g_heads; \
366 s |= (sector >> 2) & 0xc0; \
369 #if ENABLE_FEATURE_FDISK_WRITABLE
370 /* read line; return 0 or first printable char */
372 read_line(const char *prompt)
376 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
378 exit(0); /* Ctrl-D or Ctrl-C */
380 if (line_buffer[sz-1] == '\n')
381 line_buffer[--sz] = '\0';
383 line_ptr = line_buffer;
384 while (*line_ptr && !isgraph(*line_ptr))
391 * return partition name - uses static storage
394 partname(const char *dev, int pno, int lth)
401 bufp = partname_buffer;
402 bufsiz = sizeof(partname_buffer);
407 if (isdigit(dev[w-1]))
410 /* devfs kludge - note: fdisk partition names are not supposed
411 to equal kernel names, so there is no reason to do this */
412 if (strcmp(dev + w - 4, "disc") == 0) {
420 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
421 lth-wp-2, w, dev, p, pno);
423 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
428 #if ENABLE_FEATURE_FDISK_WRITABLE
430 set_all_unchanged(void)
434 for (i = 0; i < MAXIMUM_PARTS; i++)
438 static ALWAYS_INLINE void
443 #endif /* FEATURE_FDISK_WRITABLE */
445 static ALWAYS_INLINE struct partition *
446 get_part_table(int i)
448 return ptes[i].part_table;
453 { /* n==1: use singular */
455 return display_in_cyl_units ? "cylinder" : "sector";
456 return display_in_cyl_units ? "cylinders" : "sectors";
460 valid_part_table_flag(const char *mbuffer)
462 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
465 #if ENABLE_FEATURE_FDISK_WRITABLE
466 static ALWAYS_INLINE void
467 write_part_table_flag(char *b)
474 read_nonempty(const char *mesg)
476 while (!read_line(mesg)) /* repeat */;
481 read_maybe_empty(const char *mesg)
483 if (!read_line(mesg)) {
484 line_ptr = line_buffer;
492 read_hex(const char *const *sys)
496 read_nonempty("Hex code (type L to list codes): ");
497 if (*line_ptr == 'l' || *line_ptr == 'L') {
501 v = bb_strtoul(line_ptr, NULL, 16);
503 /* Bad input also triggers this */
508 #endif /* FEATURE_FDISK_WRITABLE */
510 #include "fdisk_aix.c"
513 unsigned char info[128]; /* Informative text string */
514 unsigned char spare0[14];
516 unsigned char spare1;
518 unsigned char spare2;
521 unsigned char spare1[246]; /* Boot information etc. */
522 unsigned short rspeed; /* Disk rotational speed */
523 unsigned short pcylcount; /* Physical cylinder count */
524 unsigned short sparecyl; /* extra sects per cylinder */
525 unsigned char spare2[4]; /* More magic... */
526 unsigned short ilfact; /* Interleave factor */
527 unsigned short ncyl; /* Data cylinder count */
528 unsigned short nacyl; /* Alt. cylinder count */
529 unsigned short ntrks; /* Tracks per cylinder */
530 unsigned short nsect; /* Sectors per track */
531 unsigned char spare3[4]; /* Even more magic... */
532 struct sun_partinfo {
533 uint32_t start_cylinder;
534 uint32_t num_sectors;
536 unsigned short magic; /* Magic number */
537 unsigned short csum; /* Label xor'd checksum */
539 #define sunlabel ((sun_partition *)MBRbuffer)
540 STATIC_OSF void bsd_select(void);
541 STATIC_OSF void xbsd_print_disklabel(int);
542 #include "fdisk_osf.c"
544 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
546 fdisk_swap16(uint16_t x)
548 return (x << 8) | (x >> 8);
552 fdisk_swap32(uint32_t x)
555 ((x & 0xFF00) << 8) |
556 ((x & 0xFF0000) >> 8) |
561 STATIC_SGI const char *const sgi_sys_types[];
562 STATIC_SGI unsigned sgi_get_num_sectors(int i);
563 STATIC_SGI int sgi_get_sysid(int i);
564 STATIC_SGI void sgi_delete_partition(int i);
565 STATIC_SGI void sgi_change_sysid(int i, int sys);
566 STATIC_SGI void sgi_list_table(int xtra);
567 #if ENABLE_FEATURE_FDISK_ADVANCED
568 STATIC_SGI void sgi_set_xcyl(void);
570 STATIC_SGI int verify_sgi(int verbose);
571 STATIC_SGI void sgi_add_partition(int n, int sys);
572 STATIC_SGI void sgi_set_swappartition(int i);
573 STATIC_SGI const char *sgi_get_bootfile(void);
574 STATIC_SGI void sgi_set_bootfile(const char* aFile);
575 STATIC_SGI void create_sgiinfo(void);
576 STATIC_SGI void sgi_write_table(void);
577 STATIC_SGI void sgi_set_bootpartition(int i);
578 #include "fdisk_sgi.c"
580 STATIC_SUN const char *const sun_sys_types[];
581 STATIC_SUN void sun_delete_partition(int i);
582 STATIC_SUN void sun_change_sysid(int i, int sys);
583 STATIC_SUN void sun_list_table(int xtra);
584 STATIC_SUN void add_sun_partition(int n, int sys);
585 #if ENABLE_FEATURE_FDISK_ADVANCED
586 STATIC_SUN void sun_set_alt_cyl(void);
587 STATIC_SUN void sun_set_ncyl(int cyl);
588 STATIC_SUN void sun_set_xcyl(void);
589 STATIC_SUN void sun_set_ilfact(void);
590 STATIC_SUN void sun_set_rspeed(void);
591 STATIC_SUN void sun_set_pcylcount(void);
593 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
594 STATIC_SUN void verify_sun(void);
595 STATIC_SUN void sun_write_table(void);
596 #include "fdisk_sun.c"
598 #if ENABLE_FEATURE_FDISK_WRITABLE
599 /* start_sect and nr_sects are stored little endian on all machines */
600 /* moreover, they are not aligned correctly */
602 store4_little_endian(unsigned char *cp, unsigned val)
609 #endif /* FEATURE_FDISK_WRITABLE */
612 read4_little_endian(const unsigned char *cp)
614 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
617 #if ENABLE_FEATURE_FDISK_WRITABLE
619 set_start_sect(struct partition *p, unsigned start_sect)
621 store4_little_endian(p->start4, start_sect);
626 get_start_sect(const struct partition *p)
628 return read4_little_endian(p->start4);
631 #if ENABLE_FEATURE_FDISK_WRITABLE
633 set_nr_sects(struct partition *p, unsigned nr_sects)
635 store4_little_endian(p->size4, nr_sects);
640 get_nr_sects(const struct partition *p)
642 return read4_little_endian(p->size4);
645 /* normally O_RDWR, -l option gives O_RDONLY */
646 static int type_open = O_RDWR;
648 static int ext_index; /* the prime extended partition */
649 static smallint listing; /* no aborts for fdisk -l */
650 static smallint dos_compatible_flag = 1;
651 #if ENABLE_FEATURE_FDISK_WRITABLE
652 //static int dos_changed;
653 static smallint nowarn; /* no warnings for fdisk -l/-s */
656 static unsigned user_cylinders, user_heads, user_sectors;
657 static unsigned pt_heads, pt_sectors;
658 static unsigned kern_heads, kern_sectors;
660 static ullong extended_offset; /* offset of link pointers */
661 static ullong total_number_of_sectors;
663 static void fdisk_fatal(const char *why)
667 longjmp(listingbuf, 1);
669 bb_error_msg_and_die(why, disk_device);
673 seek_sector(ullong secno)
675 secno *= sector_size;
676 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
677 if (lseek64(fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
678 fdisk_fatal(unable_to_seek);
680 if (secno > MAXINT(off_t)
681 || lseek(fd, (off_t)secno, SEEK_SET) == (off_t) -1
683 fdisk_fatal(unable_to_seek);
688 #if ENABLE_FEATURE_FDISK_WRITABLE
690 write_sector(ullong secno, char *buf)
693 if (write(fd, buf, sector_size) != sector_size)
694 fdisk_fatal(unable_to_write);
698 /* Allocate a buffer and read a partition table sector */
700 read_pte(struct pte *pe, ullong offset)
703 pe->sectorbuffer = xmalloc(sector_size);
705 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
706 fdisk_fatal(unable_to_read);
707 #if ENABLE_FEATURE_FDISK_WRITABLE
710 pe->part_table = pe->ext_pointer = NULL;
714 get_partition_start(const struct pte *pe)
716 return pe->offset + get_start_sect(pe->part_table);
719 #if ENABLE_FEATURE_FDISK_WRITABLE
721 * Avoid warning about DOS partitions when no DOS partition was changed.
722 * Here a heuristic "is probably dos partition".
723 * We might also do the opposite and warn in all cases except
724 * for "is probably nondos partition".
728 is_dos_partition(int t)
730 return (t == 1 || t == 4 || t == 6 ||
731 t == 0x0b || t == 0x0c || t == 0x0e ||
732 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
733 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
734 t == 0xc1 || t == 0xc4 || t == 0xc6);
741 puts("Command Action");
743 puts("a\ttoggle a read only flag"); /* sun */
744 puts("b\tedit bsd disklabel");
745 puts("c\ttoggle the mountable flag"); /* sun */
746 puts("d\tdelete a partition");
747 puts("l\tlist known partition types");
748 puts("n\tadd a new partition");
749 puts("o\tcreate a new empty DOS partition table");
750 puts("p\tprint the partition table");
751 puts("q\tquit without saving changes");
752 puts("s\tcreate a new empty Sun disklabel"); /* sun */
753 puts("t\tchange a partition's system id");
754 puts("u\tchange display/entry units");
755 puts("v\tverify the partition table");
756 puts("w\twrite table to disk and exit");
757 #if ENABLE_FEATURE_FDISK_ADVANCED
758 puts("x\textra functionality (experts only)");
760 } else if (LABEL_IS_SGI) {
761 puts("a\tselect bootable partition"); /* sgi flavour */
762 puts("b\tedit bootfile entry"); /* sgi */
763 puts("c\tselect sgi swap partition"); /* sgi flavour */
764 puts("d\tdelete a partition");
765 puts("l\tlist known partition types");
766 puts("n\tadd a new partition");
767 puts("o\tcreate a new empty DOS partition table");
768 puts("p\tprint the partition table");
769 puts("q\tquit without saving changes");
770 puts("s\tcreate a new empty Sun disklabel"); /* sun */
771 puts("t\tchange a partition's system id");
772 puts("u\tchange display/entry units");
773 puts("v\tverify the partition table");
774 puts("w\twrite table to disk and exit");
775 } else if (LABEL_IS_AIX) {
776 puts("o\tcreate a new empty DOS partition table");
777 puts("q\tquit without saving changes");
778 puts("s\tcreate a new empty Sun disklabel"); /* sun */
780 puts("a\ttoggle a bootable flag");
781 puts("b\tedit bsd disklabel");
782 puts("c\ttoggle the dos compatibility flag");
783 puts("d\tdelete a partition");
784 puts("l\tlist known partition types");
785 puts("n\tadd a new partition");
786 puts("o\tcreate a new empty DOS partition table");
787 puts("p\tprint the partition table");
788 puts("q\tquit without saving changes");
789 puts("s\tcreate a new empty Sun disklabel"); /* sun */
790 puts("t\tchange a partition's system id");
791 puts("u\tchange display/entry units");
792 puts("v\tverify the partition table");
793 puts("w\twrite table to disk and exit");
794 #if ENABLE_FEATURE_FDISK_ADVANCED
795 puts("x\textra functionality (experts only)");
799 #endif /* FEATURE_FDISK_WRITABLE */
802 #if ENABLE_FEATURE_FDISK_ADVANCED
806 puts("Command Action");
808 puts("a\tchange number of alternate cylinders"); /*sun*/
809 puts("c\tchange number of cylinders");
810 puts("d\tprint the raw data in the partition table");
811 puts("e\tchange number of extra sectors per cylinder");/*sun*/
812 puts("h\tchange number of heads");
813 puts("i\tchange interleave factor"); /*sun*/
814 puts("o\tchange rotation speed (rpm)"); /*sun*/
815 puts("p\tprint the partition table");
816 puts("q\tquit without saving changes");
817 puts("r\treturn to main menu");
818 puts("s\tchange number of sectors/track");
819 puts("v\tverify the partition table");
820 puts("w\twrite table to disk and exit");
821 puts("y\tchange number of physical cylinders"); /*sun*/
822 } else if (LABEL_IS_SGI) {
823 puts("b\tmove beginning of data in a partition"); /* !sun */
824 puts("c\tchange number of cylinders");
825 puts("d\tprint the raw data in the partition table");
826 puts("e\tlist extended partitions"); /* !sun */
827 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
828 puts("h\tchange number of heads");
829 puts("p\tprint the partition table");
830 puts("q\tquit without saving changes");
831 puts("r\treturn to main menu");
832 puts("s\tchange number of sectors/track");
833 puts("v\tverify the partition table");
834 puts("w\twrite table to disk and exit");
835 } else if (LABEL_IS_AIX) {
836 puts("b\tmove beginning of data in a partition"); /* !sun */
837 puts("c\tchange number of cylinders");
838 puts("d\tprint the raw data in the partition table");
839 puts("e\tlist extended partitions"); /* !sun */
840 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
841 puts("h\tchange number of heads");
842 puts("p\tprint the partition table");
843 puts("q\tquit without saving changes");
844 puts("r\treturn to main menu");
845 puts("s\tchange number of sectors/track");
846 puts("v\tverify the partition table");
847 puts("w\twrite table to disk and exit");
849 puts("b\tmove beginning of data in a partition"); /* !sun */
850 puts("c\tchange number of cylinders");
851 puts("d\tprint the raw data in the partition table");
852 puts("e\tlist extended partitions"); /* !sun */
853 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
854 #if ENABLE_FEATURE_SGI_LABEL
855 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
857 puts("h\tchange number of heads");
858 puts("p\tprint the partition table");
859 puts("q\tquit without saving changes");
860 puts("r\treturn to main menu");
861 puts("s\tchange number of sectors/track");
862 puts("v\tverify the partition table");
863 puts("w\twrite table to disk and exit");
866 #endif /* ADVANCED mode */
868 #if ENABLE_FEATURE_FDISK_WRITABLE
869 static const char *const *
873 LABEL_IS_SUN ? sun_sys_types :
874 LABEL_IS_SGI ? sgi_sys_types :
878 #define get_sys_types() i386_sys_types
879 #endif /* FEATURE_FDISK_WRITABLE */
882 partition_type(unsigned char type)
885 const char *const *types = get_sys_types();
887 for (i = 0; types[i]; i++)
888 if ((unsigned char)types[i][0] == type)
895 #if ENABLE_FEATURE_FDISK_WRITABLE
899 return LABEL_IS_SUN ? sunlabel->infos[i].id :
900 (LABEL_IS_SGI ? sgi_get_sysid(i) :
901 ptes[i].part_table->sys_ind);
905 list_types(const char *const *sys)
910 unsigned done, next, size;
913 for (size = 0; sys[size]; size++) /* */;
916 for (i = COLS-1; i >= 0; i--) {
917 done += (size + i - done) / (i + 1);
918 last[COLS-1 - i] = done;
923 printf("%c%2x %-22.22s", i ? ' ' : '\n',
924 (unsigned char)sys[next][0],
926 next = last[i++] + done;
927 if (i >= COLS || next >= last[i]) {
931 } while (done < last[0]);
934 #endif /* FEATURE_FDISK_WRITABLE */
937 is_cleared_partition(const struct partition *p)
939 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
940 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
941 get_start_sect(p) || get_nr_sects(p));
945 clear_partition(struct partition *p)
949 memset(p, 0, sizeof(struct partition));
952 #if ENABLE_FEATURE_FDISK_WRITABLE
954 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
960 p = ptes[i].ext_pointer;
961 offset = extended_offset;
963 p = ptes[i].part_table;
964 offset = ptes[i].offset;
968 set_start_sect(p, start - offset);
969 set_nr_sects(p, stop - start + 1);
970 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
971 start = g_heads * g_sectors * 1024 - 1;
972 set_hsc(p->head, p->sector, p->cyl, start);
973 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
974 stop = g_heads * g_sectors * 1024 - 1;
975 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
983 if (g_heads && g_sectors && g_cylinders)
986 printf("Unknown value(s) for:");
992 printf(" cylinders");
994 #if ENABLE_FEATURE_FDISK_WRITABLE
995 " (settable in the extra functions menu)"
1004 int cyl_units = g_heads * g_sectors;
1006 if (display_in_cyl_units && cyl_units)
1007 units_per_sector = cyl_units;
1009 units_per_sector = 1; /* in sectors */
1012 #if ENABLE_FEATURE_FDISK_WRITABLE
1014 warn_cylinders(void)
1016 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1018 "The number of cylinders for this disk is set to %d.\n"
1019 "There is nothing wrong with that, but this is larger than 1024,\n"
1020 "and could in certain setups cause problems with:\n"
1021 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1022 "2) booting and partitioning software from other OSs\n"
1023 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1029 read_extended(int ext)
1033 struct partition *p, *q;
1037 pex->ext_pointer = pex->part_table;
1039 p = pex->part_table;
1040 if (!get_start_sect(p)) {
1041 printf("Bad offset in primary extended partition\n");
1045 while (IS_EXTENDED(p->sys_ind)) {
1046 struct pte *pe = &ptes[g_partitions];
1048 if (g_partitions >= MAXIMUM_PARTS) {
1049 /* This is not a Linux restriction, but
1050 this program uses arrays of size MAXIMUM_PARTS.
1051 Do not try to 'improve' this test. */
1052 struct pte *pre = &ptes[g_partitions - 1];
1053 #if ENABLE_FEATURE_FDISK_WRITABLE
1054 printf("Warning: deleting partitions after %d\n",
1058 clear_partition(pre->ext_pointer);
1062 read_pte(pe, extended_offset + get_start_sect(p));
1064 if (!extended_offset)
1065 extended_offset = get_start_sect(p);
1067 q = p = pt_offset(pe->sectorbuffer, 0);
1068 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1069 if (IS_EXTENDED(p->sys_ind)) {
1070 if (pe->ext_pointer)
1071 printf("Warning: extra link "
1072 "pointer in partition table"
1073 " %d\n", g_partitions + 1);
1075 pe->ext_pointer = p;
1076 } else if (p->sys_ind) {
1078 printf("Warning: ignoring extra "
1079 "data in partition table"
1080 " %d\n", g_partitions + 1);
1086 /* very strange code here... */
1087 if (!pe->part_table) {
1088 if (q != pe->ext_pointer)
1091 pe->part_table = q + 1;
1093 if (!pe->ext_pointer) {
1094 if (q != pe->part_table)
1095 pe->ext_pointer = q;
1097 pe->ext_pointer = q + 1;
1100 p = pe->ext_pointer;
1104 #if ENABLE_FEATURE_FDISK_WRITABLE
1105 /* remove empty links */
1107 for (i = 4; i < g_partitions; i++) {
1108 struct pte *pe = &ptes[i];
1110 if (!get_nr_sects(pe->part_table)
1111 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1113 printf("Omitting empty partition (%d)\n", i+1);
1114 delete_partition(i);
1115 goto remove; /* numbering changed */
1121 #if ENABLE_FEATURE_FDISK_WRITABLE
1123 create_doslabel(void)
1127 printf(msg_building_new_label, "DOS disklabel");
1129 current_label_type = label_dos;
1131 #if ENABLE_FEATURE_OSF_LABEL
1132 possibly_osf_label = 0;
1136 for (i = 510-64; i < 510; i++)
1138 write_part_table_flag(MBRbuffer);
1139 extended_offset = 0;
1140 set_all_unchanged();
1142 get_boot(create_empty_dos);
1144 #endif /* FEATURE_FDISK_WRITABLE */
1147 get_sectorsize(void)
1149 if (!user_set_sector_size) {
1151 if (ioctl(fd, BLKSSZGET, &arg) == 0)
1153 if (sector_size != DEFAULT_SECTOR_SIZE)
1154 printf("Note: sector size is %d (not %d)\n",
1155 sector_size, DEFAULT_SECTOR_SIZE);
1160 get_kernel_geometry(void)
1162 struct hd_geometry geometry;
1164 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
1165 kern_heads = geometry.heads;
1166 kern_sectors = geometry.sectors;
1167 /* never use geometry.cylinders - it is truncated */
1172 get_partition_table_geometry(void)
1174 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1175 struct partition *p;
1176 int i, h, s, hh, ss;
1180 if (!(valid_part_table_flag((char*)bufp)))
1184 for (i = 0; i < 4; i++) {
1185 p = pt_offset(bufp, i);
1186 if (p->sys_ind != 0) {
1187 h = p->end_head + 1;
1188 s = (p->end_sector & 077);
1193 } else if (hh != h || ss != s)
1198 if (!first && !bad) {
1210 sec_fac = sector_size / 512;
1211 #if ENABLE_FEATURE_SUN_LABEL
1212 guess_device_type();
1214 g_heads = g_cylinders = g_sectors = 0;
1215 kern_heads = kern_sectors = 0;
1216 pt_heads = pt_sectors = 0;
1218 get_kernel_geometry();
1219 get_partition_table_geometry();
1221 g_heads = user_heads ? user_heads :
1222 pt_heads ? pt_heads :
1223 kern_heads ? kern_heads : 255;
1224 g_sectors = user_sectors ? user_sectors :
1225 pt_sectors ? pt_sectors :
1226 kern_sectors ? kern_sectors : 63;
1227 total_number_of_sectors = bb_BLKGETSIZE_sectors();
1230 if (dos_compatible_flag)
1231 sector_offset = g_sectors;
1233 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1235 g_cylinders = user_cylinders;
1239 * Read MBR. Returns:
1240 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1241 * 0: found or created label
1244 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1245 static int get_boot(enum action what)
1247 static int get_boot(void)
1248 #define get_boot(what) get_boot()
1255 for (i = 0; i < 4; i++) {
1256 struct pte *pe = &ptes[i];
1258 pe->part_table = pt_offset(MBRbuffer, i);
1259 pe->ext_pointer = NULL;
1261 pe->sectorbuffer = MBRbuffer;
1262 #if ENABLE_FEATURE_FDISK_WRITABLE
1263 pe->changed = (what == create_empty_dos);
1267 #if ENABLE_FEATURE_SUN_LABEL
1268 if (what == create_empty_sun && check_sun_label())
1272 memset(MBRbuffer, 0, 512);
1274 #if ENABLE_FEATURE_FDISK_WRITABLE
1275 if (what == create_empty_dos)
1276 goto got_dos_table; /* skip reading disk */
1278 fd = open(disk_device, type_open);
1280 fd = open(disk_device, O_RDONLY);
1282 if (what == try_only)
1284 fdisk_fatal(unable_to_open);
1286 printf("You will not be able to write "
1287 "the partition table\n");
1290 if (512 != read(fd, MBRbuffer, 512)) {
1291 if (what == try_only)
1293 fdisk_fatal(unable_to_read);
1296 fd = open(disk_device, O_RDONLY);
1299 if (512 != read(fd, MBRbuffer, 512))
1307 #if ENABLE_FEATURE_SUN_LABEL
1308 if (check_sun_label())
1312 #if ENABLE_FEATURE_SGI_LABEL
1313 if (check_sgi_label())
1317 #if ENABLE_FEATURE_AIX_LABEL
1318 if (check_aix_label())
1322 #if ENABLE_FEATURE_OSF_LABEL
1323 if (check_osf_label()) {
1324 possibly_osf_label = 1;
1325 if (!valid_part_table_flag(MBRbuffer)) {
1326 current_label_type = label_osf;
1329 printf("This disk has both DOS and BSD magic.\n"
1330 "Give the 'b' command to go to BSD mode.\n");
1334 #if ENABLE_FEATURE_FDISK_WRITABLE
1338 if (!valid_part_table_flag(MBRbuffer)) {
1339 #if !ENABLE_FEATURE_FDISK_WRITABLE
1344 printf("Device contains neither a valid DOS "
1345 "partition table, nor Sun, SGI or OSF "
1348 #if ENABLE_FEATURE_SUN_LABEL
1357 case create_empty_dos:
1358 #if ENABLE_FEATURE_SUN_LABEL
1359 case create_empty_sun:
1363 bb_error_msg_and_die("internal error");
1365 #endif /* FEATURE_FDISK_WRITABLE */
1368 #if ENABLE_FEATURE_FDISK_WRITABLE
1373 for (i = 0; i < 4; i++) {
1374 struct pte *pe = &ptes[i];
1376 if (IS_EXTENDED(pe->part_table->sys_ind)) {
1377 if (g_partitions != 4)
1378 printf("Ignoring extra extended "
1379 "partition %d\n", i + 1);
1385 for (i = 3; i < g_partitions; i++) {
1386 struct pte *pe = &ptes[i];
1388 if (!valid_part_table_flag(pe->sectorbuffer)) {
1389 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1390 "table %d will be corrected by w(rite)\n",
1391 pe->sectorbuffer[510],
1392 pe->sectorbuffer[511],
1394 #if ENABLE_FEATURE_FDISK_WRITABLE
1403 #if ENABLE_FEATURE_FDISK_WRITABLE
1405 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1406 * If the user hits Enter, DFLT is returned.
1407 * Answers like +10 are interpreted as offsets from BASE.
1409 * There is no default if DFLT is not between LOW and HIGH.
1412 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1416 const char *fmt = "%s (%u-%u, default %u): ";
1418 if (dflt < low || dflt > high) {
1419 fmt = "%s (%u-%u): ";
1424 int use_default = default_ok;
1426 /* ask question and read answer */
1428 printf(fmt, mesg, low, high, dflt);
1429 read_maybe_empty("");
1430 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1431 && *line_ptr != '-' && *line_ptr != '+');
1433 if (*line_ptr == '+' || *line_ptr == '-') {
1434 int minus = (*line_ptr == '-');
1437 i = atoi(line_ptr + 1);
1439 while (isdigit(*++line_ptr))
1442 switch (*line_ptr) {
1445 if (!display_in_cyl_units)
1446 i *= g_heads * g_sectors;
1460 absolute = 1000000000;
1469 bytes = (ullong) i * absolute;
1470 unit = sector_size * units_per_sector;
1471 bytes += unit/2; /* round */
1480 while (isdigit(*line_ptr)) {
1487 printf("Using default value %u\n", i);
1489 if (i >= low && i <= high)
1491 printf("Value is out of range\n");
1497 get_partition(int warn, int max)
1502 i = read_int(1, 0, max, 0, "Partition number") - 1;
1506 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1507 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1508 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1510 printf("Warning: partition %d has empty type\n", i+1);
1517 get_existing_partition(int warn, int max)
1522 for (i = 0; i < max; i++) {
1523 struct pte *pe = &ptes[i];
1524 struct partition *p = pe->part_table;
1526 if (p && !is_cleared_partition(p)) {
1533 printf("Selected partition %d\n", pno+1);
1536 printf("No partition is defined yet!\n");
1540 return get_partition(warn, max);
1544 get_nonexisting_partition(int warn, int max)
1549 for (i = 0; i < max; i++) {
1550 struct pte *pe = &ptes[i];
1551 struct partition *p = pe->part_table;
1553 if (p && is_cleared_partition(p)) {
1560 printf("Selected partition %d\n", pno+1);
1563 printf("All primary partitions have been defined already!\n");
1567 return get_partition(warn, max);
1574 display_in_cyl_units = !display_in_cyl_units;
1576 printf("Changing display/entry units to %s\n",
1581 toggle_active(int i)
1583 struct pte *pe = &ptes[i];
1584 struct partition *p = pe->part_table;
1586 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1587 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1588 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1593 toggle_dos_compatibility_flag(void)
1595 dos_compatible_flag = 1 - dos_compatible_flag;
1596 if (dos_compatible_flag) {
1597 sector_offset = g_sectors;
1598 printf("DOS Compatibility flag is set\n");
1601 printf("DOS Compatibility flag is not set\n");
1606 delete_partition(int i)
1608 struct pte *pe = &ptes[i];
1609 struct partition *p = pe->part_table;
1610 struct partition *q = pe->ext_pointer;
1612 /* Note that for the fifth partition (i == 4) we don't actually
1613 * decrement partitions.
1616 if (warn_geometry())
1617 return; /* C/H/S not set */
1621 sun_delete_partition(i);
1625 sgi_delete_partition(i);
1630 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1632 ptes[ext_index].ext_pointer = NULL;
1633 extended_offset = 0;
1639 if (!q->sys_ind && i > 4) {
1640 /* the last one in the chain - just delete */
1643 clear_partition(ptes[i].ext_pointer);
1644 ptes[i].changed = 1;
1646 /* not the last one - further ones will be moved down */
1648 /* delete this link in the chain */
1649 p = ptes[i-1].ext_pointer;
1651 set_start_sect(p, get_start_sect(q));
1652 set_nr_sects(p, get_nr_sects(q));
1653 ptes[i-1].changed = 1;
1654 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1655 /* the first logical in a longer chain */
1658 if (pe->part_table) /* prevent SEGFAULT */
1659 set_start_sect(pe->part_table,
1660 get_partition_start(pe) -
1662 pe->offset = extended_offset;
1666 if (g_partitions > 5) {
1668 while (i < g_partitions) {
1669 ptes[i] = ptes[i+1];
1673 /* the only logical: clear only */
1674 clear_partition(ptes[i].part_table);
1681 int i, sys, origsys;
1682 struct partition *p;
1684 /* If sgi_label then don't use get_existing_partition,
1685 let the user select a partition, since get_existing_partition()
1686 only works for Linux like partition tables. */
1687 if (!LABEL_IS_SGI) {
1688 i = get_existing_partition(0, g_partitions);
1690 i = get_partition(0, g_partitions);
1694 p = ptes[i].part_table;
1695 origsys = sys = get_sysid(i);
1697 /* if changing types T to 0 is allowed, then
1698 the reverse change must be allowed, too */
1699 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1700 printf("Partition %d does not exist yet!\n", i + 1);
1704 sys = read_hex(get_sys_types());
1706 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1707 printf("Type 0 means free space to many systems\n"
1708 "(but not to Linux). Having partitions of\n"
1709 "type 0 is probably unwise.\n");
1713 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1714 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1715 printf("You cannot change a partition into"
1716 " an extended one or vice versa\n");
1722 #if ENABLE_FEATURE_SUN_LABEL
1723 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1724 printf("Consider leaving partition 3 "
1725 "as Whole disk (5),\n"
1726 "as SunOS/Solaris expects it and "
1727 "even Linux likes it\n\n");
1729 #if ENABLE_FEATURE_SGI_LABEL
1732 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1733 (i == 8 && sys != 0)
1736 printf("Consider leaving partition 9 "
1737 "as volume header (0),\nand "
1738 "partition 11 as entire volume (6)"
1739 "as IRIX expects it\n\n");
1745 sun_change_sysid(i, sys);
1746 } else if (LABEL_IS_SGI) {
1747 sgi_change_sysid(i, sys);
1751 printf("Changed system type of partition %d "
1752 "to %x (%s)\n", i + 1, sys,
1753 partition_type(sys));
1754 ptes[i].changed = 1;
1755 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1761 #endif /* FEATURE_FDISK_WRITABLE */
1764 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1765 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1766 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1767 * Lubkin Oct. 1991). */
1770 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1772 int spc = g_heads * g_sectors;
1776 *h = ls / g_sectors;
1777 *s = ls % g_sectors + 1; /* sectors count from 1 */
1781 check_consistency(const struct partition *p, int partition)
1783 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1784 unsigned pec, peh, pes; /* physical ending c, h, s */
1785 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1786 unsigned lec, leh, les; /* logical ending c, h, s */
1788 if (!g_heads || !g_sectors || (partition >= 4))
1789 return; /* do not check extended partitions */
1791 /* physical beginning c, h, s */
1792 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1794 pbs = p->sector & 0x3f;
1796 /* physical ending c, h, s */
1797 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1799 pes = p->end_sector & 0x3f;
1801 /* compute logical beginning (c, h, s) */
1802 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1804 /* compute logical ending (c, h, s) */
1805 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1807 /* Same physical / logical beginning? */
1808 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1809 printf("Partition %d has different physical/logical "
1810 "beginnings (non-Linux?):\n", partition + 1);
1811 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1812 printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
1815 /* Same physical / logical ending? */
1816 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1817 printf("Partition %d has different physical/logical "
1818 "endings:\n", partition + 1);
1819 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1820 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1823 /* Ending on cylinder boundary? */
1824 if (peh != (g_heads - 1) || pes != g_sectors) {
1825 printf("Partition %i does not end on cylinder boundary\n",
1831 list_disk_geometry(void)
1833 long long bytes = (total_number_of_sectors << 9);
1834 long megabytes = bytes/1000000;
1836 if (megabytes < 10000)
1837 printf("\nDisk %s: %ld MB, %lld bytes\n",
1838 disk_device, megabytes, bytes);
1840 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1841 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1842 printf("%d heads, %d sectors/track, %d cylinders",
1843 g_heads, g_sectors, g_cylinders);
1844 if (units_per_sector == 1)
1845 printf(", total %llu sectors",
1846 total_number_of_sectors / (sector_size/512));
1847 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1849 units_per_sector, sector_size, units_per_sector * sector_size);
1853 * Check whether partition entries are ordered by their starting positions.
1854 * Return 0 if OK. Return i if partition i should have been earlier.
1855 * Two separate checks: primary and logical partitions.
1858 wrong_p_order(int *prev)
1860 const struct pte *pe;
1861 const struct partition *p;
1862 ullong last_p_start_pos = 0, p_start_pos;
1865 for (i = 0; i < g_partitions; i++) {
1868 last_p_start_pos = 0;
1873 p_start_pos = get_partition_start(pe);
1875 if (last_p_start_pos > p_start_pos) {
1881 last_p_start_pos = p_start_pos;
1888 #if ENABLE_FEATURE_FDISK_ADVANCED
1890 * Fix the chain of logicals.
1891 * extended_offset is unchanged, the set of sectors used is unchanged
1892 * The chain is sorted so that sectors increase, and so that
1893 * starting sectors increase.
1895 * After this it may still be that cfdisk doesnt like the table.
1896 * (This is because cfdisk considers expanded parts, from link to
1897 * end of partition, and these may still overlap.)
1899 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1903 fix_chain_of_logicals(void)
1905 int j, oj, ojj, sj, sjj;
1906 struct partition *pj,*pjj,tmp;
1908 /* Stage 1: sort sectors but leave sector of part 4 */
1909 /* (Its sector is the global extended_offset.) */
1911 for (j = 5; j < g_partitions - 1; j++) {
1912 oj = ptes[j].offset;
1913 ojj = ptes[j+1].offset;
1915 ptes[j].offset = ojj;
1916 ptes[j+1].offset = oj;
1917 pj = ptes[j].part_table;
1918 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1919 pjj = ptes[j+1].part_table;
1920 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1921 set_start_sect(ptes[j-1].ext_pointer,
1922 ojj-extended_offset);
1923 set_start_sect(ptes[j].ext_pointer,
1924 oj-extended_offset);
1929 /* Stage 2: sort starting sectors */
1931 for (j = 4; j < g_partitions - 1; j++) {
1932 pj = ptes[j].part_table;
1933 pjj = ptes[j+1].part_table;
1934 sj = get_start_sect(pj);
1935 sjj = get_start_sect(pjj);
1936 oj = ptes[j].offset;
1937 ojj = ptes[j+1].offset;
1938 if (oj+sj > ojj+sjj) {
1942 set_start_sect(pj, ojj+sjj-oj);
1943 set_start_sect(pjj, oj+sj-ojj);
1948 /* Probably something was changed */
1949 for (j = 4; j < g_partitions; j++)
1950 ptes[j].changed = 1;
1955 fix_partition_table_order(void)
1957 struct pte *pei, *pek;
1960 if (!wrong_p_order(NULL)) {
1961 printf("Ordering is already correct\n\n");
1965 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1966 /* partition i should have come earlier, move it */
1967 /* We have to move data in the MBR */
1968 struct partition *pi, *pk, *pe, pbuf;
1972 pe = pei->ext_pointer;
1973 pei->ext_pointer = pek->ext_pointer;
1974 pek->ext_pointer = pe;
1976 pi = pei->part_table;
1977 pk = pek->part_table;
1979 memmove(&pbuf, pi, sizeof(struct partition));
1980 memmove(pi, pk, sizeof(struct partition));
1981 memmove(pk, &pbuf, sizeof(struct partition));
1983 pei->changed = pek->changed = 1;
1987 fix_chain_of_logicals();
1995 list_table(int xtra)
1997 const struct partition *p;
2001 sun_list_table(xtra);
2005 sgi_list_table(xtra);
2009 list_disk_geometry();
2012 xbsd_print_disklabel(xtra);
2016 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2017 but if the device name ends in a digit, say /dev/foo1,
2018 then the partition is called /dev/foo1p3. */
2019 w = strlen(disk_device);
2020 if (w && isdigit(disk_device[w-1]))
2025 // 1 12345678901 12345678901 12345678901 12
2026 printf("%*s Boot Start End Blocks Id System\n",
2029 for (i = 0; i < g_partitions; i++) {
2030 const struct pte *pe = &ptes[i];
2036 if (!p || is_cleared_partition(p))
2039 psects = get_nr_sects(p);
2043 if (sector_size < 1024) {
2044 pblocks /= (1024 / sector_size);
2045 podd = psects % (1024 / sector_size);
2047 if (sector_size > 1024)
2048 pblocks *= (sector_size / 1024);
2050 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2051 partname(disk_device, i+1, w+2),
2052 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2054 (ullong) cround(get_partition_start(pe)), /* start */
2055 (ullong) cround(get_partition_start(pe) + psects /* end */
2056 - (psects ? 1 : 0)),
2057 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2058 p->sys_ind, /* type id */
2059 partition_type(p->sys_ind)); /* type name */
2061 check_consistency(p, i);
2064 /* Is partition table in disk order? It need not be, but... */
2065 /* partition table entries are not checked for correct order if this
2066 is a sgi, sun or aix labeled disk... */
2067 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2069 printf("\nPartition table entries are not in disk order\n");
2073 #if ENABLE_FEATURE_FDISK_ADVANCED
2075 x_list_table(int extend)
2077 const struct pte *pe;
2078 const struct partition *p;
2081 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2082 disk_device, g_heads, g_sectors, g_cylinders);
2083 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2084 for (i = 0; i < g_partitions; i++) {
2086 p = (extend ? pe->ext_pointer : pe->part_table);
2088 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2089 i + 1, p->boot_ind, p->head,
2091 cylinder(p->sector, p->cyl), p->end_head,
2092 sector(p->end_sector),
2093 cylinder(p->end_sector, p->end_cyl),
2094 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2096 check_consistency(p, i);
2102 #if ENABLE_FEATURE_FDISK_WRITABLE
2104 fill_bounds(ullong *first, ullong *last)
2107 const struct pte *pe = &ptes[0];
2108 const struct partition *p;
2110 for (i = 0; i < g_partitions; pe++,i++) {
2112 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2113 first[i] = 0xffffffff;
2116 first[i] = get_partition_start(pe);
2117 last[i] = first[i] + get_nr_sects(p) - 1;
2123 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2125 ullong total, real_s, real_c;
2127 real_s = sector(s) - 1;
2128 real_c = cylinder(s, c);
2129 total = (real_c * g_sectors + real_s) * g_heads + h;
2131 printf("Partition %d contains sector 0\n", n);
2133 printf("Partition %d: head %d greater than maximum %d\n",
2135 if (real_s >= g_sectors)
2136 printf("Partition %d: sector %d greater than "
2137 "maximum %d\n", n, s, g_sectors);
2138 if (real_c >= g_cylinders)
2139 printf("Partition %d: cylinder %llu greater than "
2140 "maximum %d\n", n, real_c + 1, g_cylinders);
2141 if (g_cylinders <= 1024 && start != total)
2142 printf("Partition %d: previous sectors %llu disagrees with "
2143 "total %llu\n", n, start, total);
2151 ullong first[g_partitions], last[g_partitions];
2152 struct partition *p;
2154 if (warn_geometry())
2166 fill_bounds(first, last);
2167 for (i = 0; i < g_partitions; i++) {
2168 struct pte *pe = &ptes[i];
2171 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2172 check_consistency(p, i);
2173 if (get_partition_start(pe) < first[i])
2174 printf("Warning: bad start-of-data in "
2175 "partition %d\n", i + 1);
2176 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2178 total += last[i] + 1 - first[i];
2179 for (j = 0; j < i; j++) {
2180 if ((first[i] >= first[j] && first[i] <= last[j])
2181 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2182 printf("Warning: partition %d overlaps "
2183 "partition %d\n", j + 1, i + 1);
2184 total += first[i] >= first[j] ?
2185 first[i] : first[j];
2186 total -= last[i] <= last[j] ?
2193 if (extended_offset) {
2194 struct pte *pex = &ptes[ext_index];
2195 ullong e_last = get_start_sect(pex->part_table) +
2196 get_nr_sects(pex->part_table) - 1;
2198 for (i = 4; i < g_partitions; i++) {
2200 p = ptes[i].part_table;
2202 if (i != 4 || i + 1 < g_partitions)
2203 printf("Warning: partition %d "
2204 "is empty\n", i + 1);
2205 } else if (first[i] < extended_offset || last[i] > e_last) {
2206 printf("Logical partition %d not entirely in "
2207 "partition %d\n", i + 1, ext_index + 1);
2212 if (total > g_heads * g_sectors * g_cylinders)
2213 printf("Total allocated sectors %d greater than the maximum "
2214 "%d\n", total, g_heads * g_sectors * g_cylinders);
2216 total = g_heads * g_sectors * g_cylinders - total;
2218 printf("%d unallocated sectors\n", total);
2223 add_partition(int n, int sys)
2225 char mesg[256]; /* 48 does not suffice in Japanese */
2226 int i, num_read = 0;
2227 struct partition *p = ptes[n].part_table;
2228 struct partition *q = ptes[ext_index].part_table;
2230 ullong start, stop = 0;
2231 ullong first[g_partitions], last[g_partitions];
2233 if (p && p->sys_ind) {
2234 printf(msg_part_already_defined, n + 1);
2237 fill_bounds(first, last);
2239 start = sector_offset;
2240 if (display_in_cyl_units || !total_number_of_sectors)
2241 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2243 limit = total_number_of_sectors - 1;
2244 if (extended_offset) {
2245 first[ext_index] = extended_offset;
2246 last[ext_index] = get_start_sect(q) +
2247 get_nr_sects(q) - 1;
2250 start = extended_offset + sector_offset;
2251 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2253 if (display_in_cyl_units)
2254 for (i = 0; i < g_partitions; i++)
2255 first[i] = (cround(first[i]) - 1) * units_per_sector;
2257 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2260 for (i = 0; i < g_partitions; i++) {
2263 if (start == ptes[i].offset)
2264 start += sector_offset;
2265 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2266 if (start >= first[i] && start <= lastplusoff)
2267 start = lastplusoff + 1;
2271 if (start >= temp+units_per_sector && num_read) {
2272 printf("Sector %lld is already allocated\n", temp);
2276 if (!num_read && start == temp) {
2279 saved_start = start;
2280 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2282 if (display_in_cyl_units) {
2283 start = (start - 1) * units_per_sector;
2284 if (start < saved_start) start = saved_start;
2288 } while (start != temp || !num_read);
2289 if (n > 4) { /* NOT for fifth partition */
2290 struct pte *pe = &ptes[n];
2292 pe->offset = start - sector_offset;
2293 if (pe->offset == extended_offset) { /* must be corrected */
2295 if (sector_offset == 1)
2300 for (i = 0; i < g_partitions; i++) {
2301 struct pte *pe = &ptes[i];
2303 if (start < pe->offset && limit >= pe->offset)
2304 limit = pe->offset - 1;
2305 if (start < first[i] && limit >= first[i])
2306 limit = first[i] - 1;
2308 if (start > limit) {
2309 printf("No free sectors available\n");
2314 if (cround(start) == cround(limit)) {
2317 snprintf(mesg, sizeof(mesg),
2318 "Last %s or +size or +sizeM or +sizeK",
2319 str_units(SINGULAR));
2320 stop = read_int(cround(start), cround(limit), cround(limit),
2321 cround(start), mesg);
2322 if (display_in_cyl_units) {
2323 stop = stop * units_per_sector - 1;
2329 set_partition(n, 0, start, stop, sys);
2331 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2333 if (IS_EXTENDED(sys)) {
2334 struct pte *pe4 = &ptes[4];
2335 struct pte *pen = &ptes[n];
2338 pen->ext_pointer = p;
2339 pe4->offset = extended_offset = start;
2340 pe4->sectorbuffer = xzalloc(sector_size);
2341 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2342 pe4->ext_pointer = pe4->part_table + 1;
2351 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2352 struct pte *pe = &ptes[g_partitions];
2354 pe->sectorbuffer = xzalloc(sector_size);
2355 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2356 pe->ext_pointer = pe->part_table + 1;
2361 add_partition(g_partitions - 1, LINUX_NATIVE);
2367 int i, free_primary = 0;
2369 if (warn_geometry())
2373 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2377 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2381 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2382 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2383 "table first (use 'o'). This will destroy the present disk contents.\n");
2387 for (i = 0; i < 4; i++)
2388 free_primary += !ptes[i].part_table->sys_ind;
2390 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2391 printf("The maximum number of partitions has been created\n");
2395 if (!free_primary) {
2396 if (extended_offset)
2399 printf("You must delete some partition and add "
2400 "an extended partition first\n");
2403 snprintf(line, sizeof(line),
2406 " p primary partition (1-4)\n",
2408 "l logical (5 or over)" : "e extended"));
2410 c = read_nonempty(line);
2411 if (c == 'p' || c == 'P') {
2412 i = get_nonexisting_partition(0, 4);
2414 add_partition(i, LINUX_NATIVE);
2417 if (c == 'l' && extended_offset) {
2421 if (c == 'e' && !extended_offset) {
2422 i = get_nonexisting_partition(0, 4);
2424 add_partition(i, EXTENDED);
2427 printf("Invalid partition number "
2428 "for type '%c'\n", c);
2439 for (i = 0; i < 3; i++)
2440 if (ptes[i].changed)
2441 ptes[3].changed = 1;
2442 for (i = 3; i < g_partitions; i++) {
2443 struct pte *pe = &ptes[i];
2446 write_part_table_flag(pe->sectorbuffer);
2447 write_sector(pe->offset, pe->sectorbuffer);
2451 else if (LABEL_IS_SGI) {
2452 /* no test on change? the printf below might be mistaken */
2455 else if (LABEL_IS_SUN) {
2458 for (i = 0; i < 8; i++)
2459 if (ptes[i].changed)
2465 printf("The partition table has been altered!\n\n");
2466 reread_partition_table(1);
2470 reread_partition_table(int leave)
2474 printf("Calling ioctl() to re-read partition table\n");
2476 /* sleep(2); Huh? */
2477 i = ioctl_or_perror(fd, BLKRRPART, NULL,
2478 "WARNING: rereading partition table "
2479 "failed, kernel still uses old table");
2483 "\nWARNING: If you have created or modified any DOS 6.x\n"
2484 "partitions, please see the fdisk manual page for additional\n"
2489 if (ENABLE_FEATURE_CLEAN_UP)
2494 #endif /* FEATURE_FDISK_WRITABLE */
2496 #if ENABLE_FEATURE_FDISK_ADVANCED
2497 #define MAX_PER_LINE 16
2499 print_buffer(char *pbuffer)
2503 for (i = 0, l = 0; i < sector_size; i++, l++) {
2505 printf("0x%03X:", i);
2506 printf(" %02X", (unsigned char) pbuffer[i]);
2507 if (l == MAX_PER_LINE - 1) {
2522 printf("Device: %s\n", disk_device);
2523 if (LABEL_IS_SGI || LABEL_IS_SUN)
2524 print_buffer(MBRbuffer);
2526 for (i = 3; i < g_partitions; i++)
2527 print_buffer(ptes[i].sectorbuffer);
2534 struct pte *pe = &ptes[i];
2535 struct partition *p = pe->part_table;
2538 if (warn_geometry())
2540 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2541 printf("Partition %d has no data area\n", i + 1);
2544 first = get_partition_start(pe);
2545 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2546 "New beginning of data") - pe->offset;
2548 if (new != get_nr_sects(p)) {
2549 first = get_nr_sects(p) + get_start_sect(p) - new;
2550 set_nr_sects(p, first);
2551 set_start_sect(p, new);
2563 c = tolower(read_nonempty("Expert command (m for help): "));
2571 move_begin(get_partition(0, g_partitions));
2574 user_cylinders = g_cylinders =
2575 read_int(1, g_cylinders, 1048576, 0,
2576 "Number of cylinders");
2578 sun_set_ncyl(g_cylinders);
2588 else if (LABEL_IS_SUN)
2590 else if (LABEL_IS_DOS)
2595 fix_partition_table_order();
2598 #if ENABLE_FEATURE_SGI_LABEL
2603 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2628 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2629 "Number of sectors");
2630 if (dos_compatible_flag) {
2631 sector_offset = g_sectors;
2632 printf("Warning: setting sector offset for DOS "
2641 write_table(); /* does not return */
2645 sun_set_pcylcount();
2652 #endif /* ADVANCED mode */
2655 is_ide_cdrom_or_tape(const char *device)
2659 struct stat statbuf;
2662 /* No device was given explicitly, and we are trying some
2663 likely things. But opening /dev/hdc may produce errors like
2664 "hdc: tray open or drive not ready"
2665 if it happens to be a CD-ROM drive. It even happens that
2666 the process hangs on the attempt to read a music CD.
2667 So try to be careful. This only works since 2.1.73. */
2669 if (strncmp("/dev/hd", device, 7))
2672 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2673 procf = fopen(buf, "r");
2674 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2675 is_ide = (!strncmp(buf, "cdrom", 5) ||
2676 !strncmp(buf, "tape", 4));
2678 /* Now when this proc file does not exist, skip the
2679 device when it is read-only. */
2680 if (stat(device, &statbuf) == 0)
2681 is_ide = ((statbuf.st_mode & 0222) == 0);
2690 trydev(const char *device, int user_specified)
2694 disk_device = device;
2695 if (setjmp(listingbuf))
2697 if (!user_specified)
2698 if (is_ide_cdrom_or_tape(device))
2700 fd = open(disk_device, type_open);
2702 gb = get_boot(try_only);
2703 if (gb > 0) { /* I/O error */
2705 } else if (gb < 0) { /* no DOS signature */
2706 list_disk_geometry();
2710 #if ENABLE_FEATURE_OSF_LABEL
2711 if (bsd_trydev(device) < 0)
2713 printf("Disk %s doesn't contain a valid "
2714 "partition table\n", device);
2719 #if ENABLE_FEATURE_FDISK_WRITABLE
2720 if (!LABEL_IS_SUN && g_partitions > 4){
2721 delete_partition(ext_index);
2726 /* Ignore other errors, since we try IDE
2727 and SCSI hard disks which may not be
2728 installed on the system. */
2729 if (errno == EACCES) {
2730 printf("Cannot open %s\n", device);
2736 /* for fdisk -l: try all things in /proc/partitions
2737 that look like a partition name (do not end in a digit) */
2742 char line[100], ptname[100], devname[120], *s;
2745 procpt = fopen_or_warn("/proc/partitions", "r");
2747 while (fgets(line, sizeof(line), procpt)) {
2748 if (sscanf(line, " %d %d %d %[^\n ]",
2749 &ma, &mi, &sz, ptname) != 4)
2751 for (s = ptname; *s; s++)
2755 sprintf(devname, "/dev/%s", ptname);
2758 #if ENABLE_FEATURE_CLEAN_UP
2763 #if ENABLE_FEATURE_FDISK_WRITABLE
2765 unknown_command(int c)
2767 printf("%c: unknown command\n", c);
2771 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2772 int fdisk_main(int argc, char **argv)
2777 * fdisk -l [-b sectorsize] [-u] device ...
2778 * fdisk -s [partition] ...
2779 * fdisk [-b sectorsize] [-u] device
2781 * Options -C, -H, -S set the geometry.
2790 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
2795 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2796 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2797 §or_size, &user_cylinders, &user_heads, &user_sectors);
2800 if (opt & OPT_b) { // -b
2801 /* Ugly: this sector size is really per device,
2802 so cannot be combined with multiple disks,
2803 and the same goes for the C/H/S options.
2805 if (sector_size != 512 && sector_size != 1024
2806 && sector_size != 2048)
2809 user_set_sector_size = 1;
2811 if (user_heads <= 0 || user_heads >= 256)
2813 if (user_sectors <= 0 || user_sectors >= 64)
2816 display_in_cyl_units = 0; // -u
2818 #if ENABLE_FEATURE_FDISK_WRITABLE
2822 type_open = O_RDONLY;
2829 /* we don't have device names, */
2830 /* use /proc/partitions instead */
2834 #if ENABLE_FEATURE_FDISK_WRITABLE
2838 #if ENABLE_FEATURE_FDISK_BLKSIZE
2845 for (j = 0; j < argc; j++) {
2846 unsigned long long size;
2847 fd = xopen(argv[j], O_RDONLY);
2848 size = bb_BLKGETSIZE_sectors() / 2;
2851 printf("%lld\n", size);
2853 printf("%s: %lld\n", argv[j], size);
2859 #if ENABLE_FEATURE_FDISK_WRITABLE
2863 disk_device = argv[0];
2867 /* OSF label, and no DOS label */
2868 printf("Detected an OSF/1 disklabel on %s, entering "
2869 "disklabel mode\n", disk_device);
2871 /*Why do we do this? It seems to be counter-intuitive*/
2872 current_label_type = label_dos;
2873 /* If we return we may want to make an empty DOS label? */
2879 c = tolower(read_nonempty("Command (m for help): "));
2883 toggle_active(get_partition(1, g_partitions));
2884 else if (LABEL_IS_SUN)
2885 toggle_sunflags(get_partition(1, g_partitions),
2887 else if (LABEL_IS_SGI)
2888 sgi_set_bootpartition(
2889 get_partition(1, g_partitions));
2895 printf("\nThe current boot file is: %s\n",
2896 sgi_get_bootfile());
2897 if (read_maybe_empty("Please enter the name of the "
2898 "new boot file: ") == '\n')
2899 printf("Boot file unchanged\n");
2901 sgi_set_bootfile(line_ptr);
2903 #if ENABLE_FEATURE_OSF_LABEL
2910 toggle_dos_compatibility_flag();
2911 else if (LABEL_IS_SUN)
2912 toggle_sunflags(get_partition(1, g_partitions),
2914 else if (LABEL_IS_SGI)
2915 sgi_set_swappartition(
2916 get_partition(1, g_partitions));
2923 /* If sgi_label then don't use get_existing_partition,
2924 let the user select a partition, since
2925 get_existing_partition() only works for Linux-like
2927 if (!LABEL_IS_SGI) {
2928 j = get_existing_partition(1, g_partitions);
2930 j = get_partition(1, g_partitions);
2933 delete_partition(j);
2942 list_types(get_sys_types());
2961 #if ENABLE_FEATURE_SUN_LABEL
2975 write_table(); /* does not return */
2977 #if ENABLE_FEATURE_FDISK_ADVANCED
2980 printf("\n\tSorry, no experts menu for SGI "
2981 "partition tables available\n\n");
2992 #endif /* FEATURE_FDISK_WRITABLE */