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 DEFAULT_SECTOR_SIZE_STR "512"
25 #define MAX_SECTOR_SIZE 2048
26 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
27 #define MAXIMUM_PARTS 60
29 #define ACTIVE_FLAG 0x80
32 #define WIN98_EXTENDED 0x0f
33 #define LINUX_PARTITION 0x81
34 #define LINUX_SWAP 0x82
35 #define LINUX_NATIVE 0x83
36 #define LINUX_EXTENDED 0x85
37 #define LINUX_LVM 0x8e
38 #define LINUX_RAID 0xfd
48 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
52 /* Used for sector numbers. Today's disk sizes make it necessary */
53 typedef unsigned long long ullong;
57 unsigned char sectors;
58 unsigned short cylinders;
62 #define HDIO_GETGEO 0x0301 /* get device geometry */
64 static const char msg_building_new_label[] ALIGN1 =
65 "Building a new %s. Changes will remain in memory only,\n"
66 "until you decide to write them. After that the previous content\n"
67 "won't be recoverable.\n\n";
69 static const char msg_part_already_defined[] ALIGN1 =
70 "Partition %d is already defined, delete it before re-adding\n";
74 unsigned char boot_ind; /* 0x80 - active */
75 unsigned char head; /* starting head */
76 unsigned char sector; /* starting sector */
77 unsigned char cyl; /* starting cylinder */
78 unsigned char sys_ind; /* what partition type */
79 unsigned char end_head; /* end head */
80 unsigned char end_sector; /* end sector */
81 unsigned char end_cyl; /* end cylinder */
82 unsigned char start4[4]; /* starting sector counting from 0 */
83 unsigned char size4[4]; /* nr of sectors in partition */
86 static const char unable_to_open[] ALIGN1 = "can't open %s";
87 static const char unable_to_read[] ALIGN1 = "can't read from %s";
88 static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
91 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
94 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
96 #if ENABLE_FEATURE_SUN_LABEL
97 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
98 #define STATIC_SUN static
100 #define LABEL_IS_SUN 0
101 #define STATIC_SUN extern
104 #if ENABLE_FEATURE_SGI_LABEL
105 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
106 #define STATIC_SGI static
108 #define LABEL_IS_SGI 0
109 #define STATIC_SGI extern
112 #if ENABLE_FEATURE_AIX_LABEL
113 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
114 #define STATIC_AIX static
116 #define LABEL_IS_AIX 0
117 #define STATIC_AIX extern
120 #if ENABLE_FEATURE_OSF_LABEL
121 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
122 #define STATIC_OSF static
124 #define LABEL_IS_OSF 0
125 #define STATIC_OSF extern
128 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
130 static void update_units(void);
131 #if ENABLE_FEATURE_FDISK_WRITABLE
132 static void change_units(void);
133 static void reread_partition_table(int leave);
134 static void delete_partition(int i);
135 static int get_partition(int warn, int max);
136 static void list_types(const char *const *sys);
137 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
139 static const char *partition_type(unsigned char type);
140 static void get_geometry(void);
141 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
142 static int get_boot(enum action what);
144 static int get_boot(void);
150 static unsigned get_start_sect(const struct partition *p);
151 static unsigned get_nr_sects(const struct partition *p);
154 * per partition table entry data
156 * The four primary partitions have the same sectorbuffer (MBRbuffer)
157 * and have NULL ext_pointer.
158 * Each logical partition table entry has two pointers, one for the
159 * partition and one link to the next one.
162 struct partition *part_table; /* points into sectorbuffer */
163 struct partition *ext_pointer; /* points into sectorbuffer */
164 ullong offset; /* disk sector number */
165 char *sectorbuffer; /* disk sector contents */
166 #if ENABLE_FEATURE_FDISK_WRITABLE
167 char changed; /* boolean */
171 /* DOS partition types */
173 static const char *const i386_sys_types[] = {
177 "\x05" "Extended", /* DOS 3.3+ extended partition */
178 "\x06" "FAT16", /* DOS 16-bit >=32M */
179 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
180 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
181 "\x0b" "Win95 FAT32",
182 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
183 "\x0e" "Win95 FAT16 (LBA)",
184 "\x0f" "Win95 Ext'd (LBA)",
185 "\x11" "Hidden FAT12",
186 "\x12" "Compaq diagnostics",
187 "\x14" "Hidden FAT16 <32M",
188 "\x16" "Hidden FAT16",
189 "\x17" "Hidden HPFS/NTFS",
190 "\x1b" "Hidden Win95 FAT32",
191 "\x1c" "Hidden W95 FAT32 (LBA)",
192 "\x1e" "Hidden W95 FAT16 (LBA)",
193 "\x3c" "Part.Magic recovery",
194 "\x41" "PPC PReP Boot",
196 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
197 "\x80" "Old Minix", /* Minix 1.4a and earlier */
198 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
199 "\x82" "Linux swap", /* also Solaris */
201 "\x84" "OS/2 hidden C: drive",
202 "\x85" "Linux extended",
203 "\x86" "NTFS volume set",
204 "\x87" "NTFS volume set",
206 "\x9f" "BSD/OS", /* BSDI */
207 "\xa0" "Thinkpad hibernation",
208 "\xa5" "FreeBSD", /* various BSD flavours */
212 "\xab" "Darwin boot",
215 "\xbe" "Solaris boot",
217 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
218 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
219 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
220 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
221 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
222 autodetect using persistent
224 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
227 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
228 "\x09" "AIX bootable", /* AIX data or Coherent */
230 "\x18" "AST SmartSleep",
233 "\x40" "Venix 80286",
235 "\x4e" "QNX4.x 2nd part",
236 "\x4f" "QNX4.x 3rd part",
238 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
239 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
240 "\x53" "OnTrack DM6 Aux3",
244 "\x5c" "Priam Edisk",
246 "\x64" "Novell Netware 286",
247 "\x65" "Novell Netware 386",
248 "\x70" "DiskSecure Multi-Boot",
251 "\x94" "Amoeba BBT", /* (bad block table) */
253 "\xbb" "Boot Wizard hidden",
254 "\xc1" "DRDOS/sec (FAT-12)",
255 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
256 "\xc6" "DRDOS/sec (FAT-16)",
258 "\xda" "Non-FS data",
259 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
260 Concurrent DOS or CTOS */
261 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
262 "\xdf" "BootIt", /* BootIt EMBRM */
263 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
264 extended partition */
265 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
266 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
267 partition < 1024 cyl. */
269 "\xf4" "SpeedStor", /* SpeedStor large partition */
270 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
271 "\xff" "BBT", /* Xenix Bad Block Table */
277 dev_fd = 3 /* the disk */
284 const char *disk_device;
285 int g_partitions; // = 4; /* maximum partition + 1 */
286 unsigned units_per_sector; // = 1;
287 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
288 unsigned user_set_sector_size;
289 unsigned sector_offset; // = 1;
290 unsigned g_heads, g_sectors, g_cylinders;
291 smallint /* enum label_type */ current_label_type;
292 smallint display_in_cyl_units; // = 1;
293 #if ENABLE_FEATURE_OSF_LABEL
294 smallint possibly_osf_label;
297 smallint listing; /* no aborts for fdisk -l */
298 smallint dos_compatible_flag; // = 1;
299 #if ENABLE_FEATURE_FDISK_WRITABLE
301 smallint nowarn; /* no warnings for fdisk -l/-s */
303 int ext_index; /* the prime extended partition */
304 unsigned user_cylinders, user_heads, user_sectors;
305 unsigned pt_heads, pt_sectors;
306 unsigned kern_heads, kern_sectors;
307 ullong extended_offset; /* offset of link pointers */
308 ullong total_number_of_sectors;
311 char line_buffer[80];
312 char partname_buffer[80];
313 /* Raw disk label. For DOS-type partition tables the MBR,
314 * with descriptions of the primary partitions. */
315 char MBRbuffer[MAX_SECTOR_SIZE];
316 /* Partition tables */
317 struct pte ptes[MAXIMUM_PARTS];
319 #define G (*ptr_to_globals)
320 #define line_ptr (G.line_ptr )
321 #define disk_device (G.disk_device )
322 #define g_partitions (G.g_partitions )
323 #define units_per_sector (G.units_per_sector )
324 #define sector_size (G.sector_size )
325 #define user_set_sector_size (G.user_set_sector_size)
326 #define sector_offset (G.sector_offset )
327 #define g_heads (G.g_heads )
328 #define g_sectors (G.g_sectors )
329 #define g_cylinders (G.g_cylinders )
330 #define current_label_type (G.current_label_type )
331 #define display_in_cyl_units (G.display_in_cyl_units)
332 #define possibly_osf_label (G.possibly_osf_label )
333 #define listing (G.listing )
334 #define dos_compatible_flag (G.dos_compatible_flag )
335 #define nowarn (G.nowarn )
336 #define ext_index (G.ext_index )
337 #define user_cylinders (G.user_cylinders )
338 #define user_heads (G.user_heads )
339 #define user_sectors (G.user_sectors )
340 #define pt_heads (G.pt_heads )
341 #define pt_sectors (G.pt_sectors )
342 #define kern_heads (G.kern_heads )
343 #define kern_sectors (G.kern_sectors )
344 #define extended_offset (G.extended_offset )
345 #define total_number_of_sectors (G.total_number_of_sectors)
346 #define listingbuf (G.listingbuf )
347 #define line_buffer (G.line_buffer )
348 #define partname_buffer (G.partname_buffer)
349 #define MBRbuffer (G.MBRbuffer )
350 #define ptes (G.ptes )
351 #define INIT_G() do { \
352 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
353 sector_size = DEFAULT_SECTOR_SIZE; \
356 display_in_cyl_units = 1; \
357 units_per_sector = 1; \
358 dos_compatible_flag = 1; \
362 /* TODO: move to libbb? */
363 static ullong bb_BLKGETSIZE_sectors(int fd)
366 unsigned long longsectors;
368 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
369 /* Got bytes, convert to 512 byte sectors */
372 /* Needs temp of type long */
373 if (ioctl(fd, BLKGETSIZE, &longsectors))
379 #define IS_EXTENDED(i) \
380 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
382 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
384 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
386 #define pt_offset(b, n) \
387 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
389 #define sector(s) ((s) & 0x3f)
391 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
393 #define hsc2sector(h,s,c) \
394 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
396 #define set_hsc(h,s,c,sector) \
398 s = sector % g_sectors + 1; \
399 sector /= g_sectors; \
400 h = sector % g_heads; \
403 s |= (sector >> 2) & 0xc0; \
409 /* Not really closing, but making sure it is open, and to harmless place */
410 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
413 #if ENABLE_FEATURE_FDISK_WRITABLE
414 /* Read line; return 0 or first printable char */
416 read_line(const char *prompt)
420 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
422 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
424 if (line_buffer[sz-1] == '\n')
425 line_buffer[--sz] = '\0';
427 line_ptr = line_buffer;
428 while (*line_ptr && !isgraph(*line_ptr))
435 * Return partition name - uses static storage
438 partname(const char *dev, int pno, int lth)
445 bufp = partname_buffer;
446 bufsiz = sizeof(partname_buffer);
451 if (isdigit(dev[w-1]))
454 /* devfs kludge - note: fdisk partition names are not supposed
455 to equal kernel names, so there is no reason to do this */
456 if (strcmp(dev + w - 4, "disc") == 0) {
464 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
465 lth-wp-2, w, dev, p, pno);
467 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
472 #if ENABLE_FEATURE_FDISK_WRITABLE
474 set_all_unchanged(void)
478 for (i = 0; i < MAXIMUM_PARTS; i++)
482 static ALWAYS_INLINE void
487 #endif /* FEATURE_FDISK_WRITABLE */
489 static ALWAYS_INLINE struct partition *
490 get_part_table(int i)
492 return ptes[i].part_table;
497 { /* n==1: use singular */
499 return display_in_cyl_units ? "cylinder" : "sector";
500 return display_in_cyl_units ? "cylinders" : "sectors";
504 valid_part_table_flag(const char *mbuffer)
506 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
509 #if ENABLE_FEATURE_FDISK_WRITABLE
510 static ALWAYS_INLINE void
511 write_part_table_flag(char *b)
518 read_nonempty(const char *mesg)
520 while (!read_line(mesg))
526 read_maybe_empty(const char *mesg)
528 if (!read_line(mesg)) {
529 line_ptr = line_buffer;
537 read_hex(const char *const *sys)
541 read_nonempty("Hex code (type L to list codes): ");
542 if (*line_ptr == 'l' || *line_ptr == 'L') {
546 v = bb_strtoul(line_ptr, NULL, 16);
548 /* Bad input also triggers this */
553 #endif /* FEATURE_FDISK_WRITABLE */
555 static void fdisk_fatal(const char *why)
559 longjmp(listingbuf, 1);
561 bb_error_msg_and_die(why, disk_device);
565 seek_sector(ullong secno)
567 secno *= sector_size;
568 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
569 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
570 fdisk_fatal(unable_to_seek);
572 if (secno > MAXINT(off_t)
573 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
575 fdisk_fatal(unable_to_seek);
580 #if ENABLE_FEATURE_FDISK_WRITABLE
582 write_sector(ullong secno, const void *buf)
585 xwrite(dev_fd, buf, sector_size);
590 #include "fdisk_aix.c"
593 unsigned char info[128]; /* Informative text string */
594 unsigned char spare0[14];
596 unsigned char spare1;
598 unsigned char spare2;
601 unsigned char spare1[246]; /* Boot information etc. */
602 unsigned short rspeed; /* Disk rotational speed */
603 unsigned short pcylcount; /* Physical cylinder count */
604 unsigned short sparecyl; /* extra sects per cylinder */
605 unsigned char spare2[4]; /* More magic... */
606 unsigned short ilfact; /* Interleave factor */
607 unsigned short ncyl; /* Data cylinder count */
608 unsigned short nacyl; /* Alt. cylinder count */
609 unsigned short ntrks; /* Tracks per cylinder */
610 unsigned short nsect; /* Sectors per track */
611 unsigned char spare3[4]; /* Even more magic... */
612 struct sun_partinfo {
613 uint32_t start_cylinder;
614 uint32_t num_sectors;
616 unsigned short magic; /* Magic number */
617 unsigned short csum; /* Label xor'd checksum */
619 #define sunlabel ((sun_partition *)MBRbuffer)
620 STATIC_OSF void bsd_select(void);
621 STATIC_OSF void xbsd_print_disklabel(int);
622 #include "fdisk_osf.c"
624 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
626 fdisk_swap16(uint16_t x)
628 return (x << 8) | (x >> 8);
632 fdisk_swap32(uint32_t x)
635 ((x & 0xFF00) << 8) |
636 ((x & 0xFF0000) >> 8) |
641 STATIC_SGI const char *const sgi_sys_types[];
642 STATIC_SGI unsigned sgi_get_num_sectors(int i);
643 STATIC_SGI int sgi_get_sysid(int i);
644 STATIC_SGI void sgi_delete_partition(int i);
645 STATIC_SGI void sgi_change_sysid(int i, int sys);
646 STATIC_SGI void sgi_list_table(int xtra);
647 #if ENABLE_FEATURE_FDISK_ADVANCED
648 STATIC_SGI void sgi_set_xcyl(void);
650 STATIC_SGI int verify_sgi(int verbose);
651 STATIC_SGI void sgi_add_partition(int n, int sys);
652 STATIC_SGI void sgi_set_swappartition(int i);
653 STATIC_SGI const char *sgi_get_bootfile(void);
654 STATIC_SGI void sgi_set_bootfile(const char* aFile);
655 STATIC_SGI void create_sgiinfo(void);
656 STATIC_SGI void sgi_write_table(void);
657 STATIC_SGI void sgi_set_bootpartition(int i);
658 #include "fdisk_sgi.c"
660 STATIC_SUN const char *const sun_sys_types[];
661 STATIC_SUN void sun_delete_partition(int i);
662 STATIC_SUN void sun_change_sysid(int i, int sys);
663 STATIC_SUN void sun_list_table(int xtra);
664 STATIC_SUN void add_sun_partition(int n, int sys);
665 #if ENABLE_FEATURE_FDISK_ADVANCED
666 STATIC_SUN void sun_set_alt_cyl(void);
667 STATIC_SUN void sun_set_ncyl(int cyl);
668 STATIC_SUN void sun_set_xcyl(void);
669 STATIC_SUN void sun_set_ilfact(void);
670 STATIC_SUN void sun_set_rspeed(void);
671 STATIC_SUN void sun_set_pcylcount(void);
673 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
674 STATIC_SUN void verify_sun(void);
675 STATIC_SUN void sun_write_table(void);
676 #include "fdisk_sun.c"
679 #if ENABLE_FEATURE_FDISK_WRITABLE
680 /* start_sect and nr_sects are stored little endian on all machines */
681 /* moreover, they are not aligned correctly */
683 store4_little_endian(unsigned char *cp, unsigned val)
690 #endif /* FEATURE_FDISK_WRITABLE */
693 read4_little_endian(const unsigned char *cp)
695 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
698 #if ENABLE_FEATURE_FDISK_WRITABLE
700 set_start_sect(struct partition *p, unsigned start_sect)
702 store4_little_endian(p->start4, start_sect);
707 get_start_sect(const struct partition *p)
709 return read4_little_endian(p->start4);
712 #if ENABLE_FEATURE_FDISK_WRITABLE
714 set_nr_sects(struct partition *p, unsigned nr_sects)
716 store4_little_endian(p->size4, nr_sects);
721 get_nr_sects(const struct partition *p)
723 return read4_little_endian(p->size4);
726 /* Allocate a buffer and read a partition table sector */
728 read_pte(struct pte *pe, ullong offset)
731 pe->sectorbuffer = xzalloc(sector_size);
733 /* xread would make us abort - bad for fdisk -l */
734 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
735 fdisk_fatal(unable_to_read);
736 #if ENABLE_FEATURE_FDISK_WRITABLE
739 pe->part_table = pe->ext_pointer = NULL;
743 get_partition_start(const struct pte *pe)
745 return pe->offset + get_start_sect(pe->part_table);
748 #if ENABLE_FEATURE_FDISK_WRITABLE
750 * Avoid warning about DOS partitions when no DOS partition was changed.
751 * Here a heuristic "is probably dos partition".
752 * We might also do the opposite and warn in all cases except
753 * for "is probably nondos partition".
757 is_dos_partition(int t)
759 return (t == 1 || t == 4 || t == 6 ||
760 t == 0x0b || t == 0x0c || t == 0x0e ||
761 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
762 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
763 t == 0xc1 || t == 0xc4 || t == 0xc6);
770 puts("Command Action");
772 puts("a\ttoggle a read only flag"); /* sun */
773 puts("b\tedit bsd disklabel");
774 puts("c\ttoggle the mountable flag"); /* sun */
775 puts("d\tdelete a partition");
776 puts("l\tlist known partition types");
777 puts("n\tadd a new partition");
778 puts("o\tcreate a new empty DOS partition table");
779 puts("p\tprint the partition table");
780 puts("q\tquit without saving changes");
781 puts("s\tcreate a new empty Sun disklabel"); /* sun */
782 puts("t\tchange a partition's system id");
783 puts("u\tchange display/entry units");
784 puts("v\tverify the partition table");
785 puts("w\twrite table to disk and exit");
786 #if ENABLE_FEATURE_FDISK_ADVANCED
787 puts("x\textra functionality (experts only)");
789 } else if (LABEL_IS_SGI) {
790 puts("a\tselect bootable partition"); /* sgi flavour */
791 puts("b\tedit bootfile entry"); /* sgi */
792 puts("c\tselect sgi swap partition"); /* sgi flavour */
793 puts("d\tdelete a partition");
794 puts("l\tlist known partition types");
795 puts("n\tadd a new partition");
796 puts("o\tcreate a new empty DOS partition table");
797 puts("p\tprint the partition table");
798 puts("q\tquit without saving changes");
799 puts("s\tcreate a new empty Sun disklabel"); /* sun */
800 puts("t\tchange a partition's system id");
801 puts("u\tchange display/entry units");
802 puts("v\tverify the partition table");
803 puts("w\twrite table to disk and exit");
804 } else if (LABEL_IS_AIX) {
805 puts("o\tcreate a new empty DOS partition table");
806 puts("q\tquit without saving changes");
807 puts("s\tcreate a new empty Sun disklabel"); /* sun */
809 puts("a\ttoggle a bootable flag");
810 puts("b\tedit bsd disklabel");
811 puts("c\ttoggle the dos compatibility flag");
812 puts("d\tdelete a partition");
813 puts("l\tlist known partition types");
814 puts("n\tadd a new partition");
815 puts("o\tcreate a new empty DOS partition table");
816 puts("p\tprint the partition table");
817 puts("q\tquit without saving changes");
818 puts("s\tcreate a new empty Sun disklabel"); /* sun */
819 puts("t\tchange a partition's system id");
820 puts("u\tchange display/entry units");
821 puts("v\tverify the partition table");
822 puts("w\twrite table to disk and exit");
823 #if ENABLE_FEATURE_FDISK_ADVANCED
824 puts("x\textra functionality (experts only)");
828 #endif /* FEATURE_FDISK_WRITABLE */
831 #if ENABLE_FEATURE_FDISK_ADVANCED
835 puts("Command Action");
837 puts("a\tchange number of alternate cylinders"); /*sun*/
838 puts("c\tchange number of cylinders");
839 puts("d\tprint the raw data in the partition table");
840 puts("e\tchange number of extra sectors per cylinder");/*sun*/
841 puts("h\tchange number of heads");
842 puts("i\tchange interleave factor"); /*sun*/
843 puts("o\tchange rotation speed (rpm)"); /*sun*/
844 puts("p\tprint the partition table");
845 puts("q\tquit without saving changes");
846 puts("r\treturn to main menu");
847 puts("s\tchange number of sectors/track");
848 puts("v\tverify the partition table");
849 puts("w\twrite table to disk and exit");
850 puts("y\tchange number of physical cylinders"); /*sun*/
851 } else if (LABEL_IS_SGI) {
852 puts("b\tmove beginning of data in a partition"); /* !sun */
853 puts("c\tchange number of cylinders");
854 puts("d\tprint the raw data in the partition table");
855 puts("e\tlist extended partitions"); /* !sun */
856 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");
864 } else if (LABEL_IS_AIX) {
865 puts("b\tmove beginning of data in a partition"); /* !sun */
866 puts("c\tchange number of cylinders");
867 puts("d\tprint the raw data in the partition table");
868 puts("e\tlist extended partitions"); /* !sun */
869 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
870 puts("h\tchange number of heads");
871 puts("p\tprint the partition table");
872 puts("q\tquit without saving changes");
873 puts("r\treturn to main menu");
874 puts("s\tchange number of sectors/track");
875 puts("v\tverify the partition table");
876 puts("w\twrite table to disk and exit");
878 puts("b\tmove beginning of data in a partition"); /* !sun */
879 puts("c\tchange number of cylinders");
880 puts("d\tprint the raw data in the partition table");
881 puts("e\tlist extended partitions"); /* !sun */
882 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
883 #if ENABLE_FEATURE_SGI_LABEL
884 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
886 puts("h\tchange number of heads");
887 puts("p\tprint the partition table");
888 puts("q\tquit without saving changes");
889 puts("r\treturn to main menu");
890 puts("s\tchange number of sectors/track");
891 puts("v\tverify the partition table");
892 puts("w\twrite table to disk and exit");
895 #endif /* ADVANCED mode */
897 #if ENABLE_FEATURE_FDISK_WRITABLE
898 static const char *const *
902 LABEL_IS_SUN ? sun_sys_types :
903 LABEL_IS_SGI ? sgi_sys_types :
907 #define get_sys_types() i386_sys_types
908 #endif /* FEATURE_FDISK_WRITABLE */
911 partition_type(unsigned char type)
914 const char *const *types = get_sys_types();
916 for (i = 0; types[i]; i++)
917 if ((unsigned char)types[i][0] == type)
924 #if ENABLE_FEATURE_FDISK_WRITABLE
928 return LABEL_IS_SUN ? sunlabel->infos[i].id :
929 (LABEL_IS_SGI ? sgi_get_sysid(i) :
930 ptes[i].part_table->sys_ind);
934 list_types(const char *const *sys)
939 unsigned done, next, size;
942 for (size = 0; sys[size]; size++)
946 for (i = COLS-1; i >= 0; i--) {
947 done += (size + i - done) / (i + 1);
948 last[COLS-1 - i] = done;
953 printf("%c%2x %-22.22s", i ? ' ' : '\n',
954 (unsigned char)sys[next][0],
956 next = last[i++] + done;
957 if (i >= COLS || next >= last[i]) {
961 } while (done < last[0]);
964 #endif /* FEATURE_FDISK_WRITABLE */
967 is_cleared_partition(const struct partition *p)
969 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
970 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
971 get_start_sect(p) || get_nr_sects(p));
975 clear_partition(struct partition *p)
979 memset(p, 0, sizeof(struct partition));
982 #if ENABLE_FEATURE_FDISK_WRITABLE
984 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
990 p = ptes[i].ext_pointer;
991 offset = extended_offset;
993 p = ptes[i].part_table;
994 offset = ptes[i].offset;
998 set_start_sect(p, start - offset);
999 set_nr_sects(p, stop - start + 1);
1000 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1001 start = g_heads * g_sectors * 1024 - 1;
1002 set_hsc(p->head, p->sector, p->cyl, start);
1003 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1004 stop = g_heads * g_sectors * 1024 - 1;
1005 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1006 ptes[i].changed = 1;
1013 if (g_heads && g_sectors && g_cylinders)
1016 printf("Unknown value(s) for:");
1022 printf(" cylinders");
1024 #if ENABLE_FEATURE_FDISK_WRITABLE
1025 " (settable in the extra functions menu)"
1034 int cyl_units = g_heads * g_sectors;
1036 if (display_in_cyl_units && cyl_units)
1037 units_per_sector = cyl_units;
1039 units_per_sector = 1; /* in sectors */
1042 #if ENABLE_FEATURE_FDISK_WRITABLE
1044 warn_cylinders(void)
1046 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1048 "The number of cylinders for this disk is set to %d.\n"
1049 "There is nothing wrong with that, but this is larger than 1024,\n"
1050 "and could in certain setups cause problems with:\n"
1051 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1052 "2) booting and partitioning software from other OSs\n"
1053 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1059 read_extended(int ext)
1063 struct partition *p, *q;
1067 pex->ext_pointer = pex->part_table;
1069 p = pex->part_table;
1070 if (!get_start_sect(p)) {
1071 printf("Bad offset in primary extended partition\n");
1075 while (IS_EXTENDED(p->sys_ind)) {
1076 struct pte *pe = &ptes[g_partitions];
1078 if (g_partitions >= MAXIMUM_PARTS) {
1079 /* This is not a Linux restriction, but
1080 this program uses arrays of size MAXIMUM_PARTS.
1081 Do not try to 'improve' this test. */
1082 struct pte *pre = &ptes[g_partitions - 1];
1083 #if ENABLE_FEATURE_FDISK_WRITABLE
1084 printf("Warning: deleting partitions after %d\n",
1088 clear_partition(pre->ext_pointer);
1092 read_pte(pe, extended_offset + get_start_sect(p));
1094 if (!extended_offset)
1095 extended_offset = get_start_sect(p);
1097 q = p = pt_offset(pe->sectorbuffer, 0);
1098 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1099 if (IS_EXTENDED(p->sys_ind)) {
1100 if (pe->ext_pointer)
1101 printf("Warning: extra link "
1102 "pointer in partition table"
1103 " %d\n", g_partitions + 1);
1105 pe->ext_pointer = p;
1106 } else if (p->sys_ind) {
1108 printf("Warning: ignoring extra "
1109 "data in partition table"
1110 " %d\n", g_partitions + 1);
1116 /* very strange code here... */
1117 if (!pe->part_table) {
1118 if (q != pe->ext_pointer)
1121 pe->part_table = q + 1;
1123 if (!pe->ext_pointer) {
1124 if (q != pe->part_table)
1125 pe->ext_pointer = q;
1127 pe->ext_pointer = q + 1;
1130 p = pe->ext_pointer;
1134 #if ENABLE_FEATURE_FDISK_WRITABLE
1135 /* remove empty links */
1137 for (i = 4; i < g_partitions; i++) {
1138 struct pte *pe = &ptes[i];
1140 if (!get_nr_sects(pe->part_table)
1141 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1143 printf("Omitting empty partition (%d)\n", i+1);
1144 delete_partition(i);
1145 goto remove; /* numbering changed */
1151 #if ENABLE_FEATURE_FDISK_WRITABLE
1153 create_doslabel(void)
1157 printf(msg_building_new_label, "DOS disklabel");
1159 current_label_type = LABEL_DOS;
1161 #if ENABLE_FEATURE_OSF_LABEL
1162 possibly_osf_label = 0;
1166 for (i = 510-64; i < 510; i++)
1168 write_part_table_flag(MBRbuffer);
1169 extended_offset = 0;
1170 set_all_unchanged();
1172 get_boot(CREATE_EMPTY_DOS);
1174 #endif /* FEATURE_FDISK_WRITABLE */
1177 get_sectorsize(void)
1179 if (!user_set_sector_size) {
1181 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1183 if (sector_size != DEFAULT_SECTOR_SIZE)
1184 printf("Note: sector size is %d "
1185 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1191 get_kernel_geometry(void)
1193 struct hd_geometry geometry;
1195 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1196 kern_heads = geometry.heads;
1197 kern_sectors = geometry.sectors;
1198 /* never use geometry.cylinders - it is truncated */
1203 get_partition_table_geometry(void)
1205 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1206 struct partition *p;
1207 int i, h, s, hh, ss;
1211 if (!(valid_part_table_flag((char*)bufp)))
1215 for (i = 0; i < 4; i++) {
1216 p = pt_offset(bufp, i);
1217 if (p->sys_ind != 0) {
1218 h = p->end_head + 1;
1219 s = (p->end_sector & 077);
1224 } else if (hh != h || ss != s)
1229 if (!first && !bad) {
1241 sec_fac = sector_size / 512;
1242 #if ENABLE_FEATURE_SUN_LABEL
1243 guess_device_type();
1245 g_heads = g_cylinders = g_sectors = 0;
1246 kern_heads = kern_sectors = 0;
1247 pt_heads = pt_sectors = 0;
1249 get_kernel_geometry();
1250 get_partition_table_geometry();
1252 g_heads = user_heads ? user_heads :
1253 pt_heads ? pt_heads :
1254 kern_heads ? kern_heads : 255;
1255 g_sectors = user_sectors ? user_sectors :
1256 pt_sectors ? pt_sectors :
1257 kern_sectors ? kern_sectors : 63;
1258 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1261 if (dos_compatible_flag)
1262 sector_offset = g_sectors;
1264 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1266 g_cylinders = user_cylinders;
1270 * Opens disk_device and optionally reads MBR.
1271 * FIXME: document what each 'what' value will do!
1273 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1274 * 0: found or created label
1277 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1278 static int get_boot(enum action what)
1280 static int get_boot(void)
1281 #define get_boot(what) get_boot()
1287 for (i = 0; i < 4; i++) {
1288 struct pte *pe = &ptes[i];
1289 pe->part_table = pt_offset(MBRbuffer, i);
1290 pe->ext_pointer = NULL;
1292 pe->sectorbuffer = MBRbuffer;
1293 #if ENABLE_FEATURE_FDISK_WRITABLE
1294 pe->changed = (what == CREATE_EMPTY_DOS);
1298 #if ENABLE_FEATURE_FDISK_WRITABLE
1299 // ALERT! highly idiotic design!
1300 // We end up here when we call get_boot() recursively
1301 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1302 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1303 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1304 // So skip opening device _again_...
1305 if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1308 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1311 fd = open(disk_device, O_RDONLY);
1313 if (what == TRY_ONLY)
1315 fdisk_fatal(unable_to_open);
1317 printf("'%s' is opened for read only\n", disk_device);
1319 xmove_fd(fd, dev_fd);
1320 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1321 if (what == TRY_ONLY) {
1325 fdisk_fatal(unable_to_read);
1328 fd = open(disk_device, O_RDONLY);
1331 if (512 != full_read(fd, MBRbuffer, 512)) {
1335 xmove_fd(fd, dev_fd);
1341 #if ENABLE_FEATURE_SUN_LABEL
1342 if (check_sun_label())
1345 #if ENABLE_FEATURE_SGI_LABEL
1346 if (check_sgi_label())
1349 #if ENABLE_FEATURE_AIX_LABEL
1350 if (check_aix_label())
1353 #if ENABLE_FEATURE_OSF_LABEL
1354 if (check_osf_label()) {
1355 possibly_osf_label = 1;
1356 if (!valid_part_table_flag(MBRbuffer)) {
1357 current_label_type = LABEL_OSF;
1360 printf("This disk has both DOS and BSD magic.\n"
1361 "Give the 'b' command to go to BSD mode.\n");
1365 #if !ENABLE_FEATURE_FDISK_WRITABLE
1366 if (!valid_part_table_flag(MBRbuffer))
1369 if (!valid_part_table_flag(MBRbuffer)) {
1370 if (what == OPEN_MAIN) {
1371 printf("Device contains neither a valid DOS "
1372 "partition table, nor Sun, SGI or OSF "
1375 USE_FEATURE_SUN_LABEL(create_sunlabel();)
1385 #endif /* FEATURE_FDISK_WRITABLE */
1388 USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1391 for (i = 0; i < 4; i++) {
1392 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1393 if (g_partitions != 4)
1394 printf("Ignoring extra extended "
1395 "partition %d\n", i + 1);
1401 for (i = 3; i < g_partitions; i++) {
1402 struct pte *pe = &ptes[i];
1403 if (!valid_part_table_flag(pe->sectorbuffer)) {
1404 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1405 "table %d will be corrected by w(rite)\n",
1406 pe->sectorbuffer[510],
1407 pe->sectorbuffer[511],
1409 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1416 #if ENABLE_FEATURE_FDISK_WRITABLE
1418 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1419 * If the user hits Enter, DFLT is returned.
1420 * Answers like +10 are interpreted as offsets from BASE.
1422 * There is no default if DFLT is not between LOW and HIGH.
1425 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1429 const char *fmt = "%s (%u-%u, default %u): ";
1431 if (dflt < low || dflt > high) {
1432 fmt = "%s (%u-%u): ";
1437 int use_default = default_ok;
1439 /* ask question and read answer */
1441 printf(fmt, mesg, low, high, dflt);
1442 read_maybe_empty("");
1443 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1444 && *line_ptr != '-' && *line_ptr != '+');
1446 if (*line_ptr == '+' || *line_ptr == '-') {
1447 int minus = (*line_ptr == '-');
1450 i = atoi(line_ptr + 1);
1452 while (isdigit(*++line_ptr))
1455 switch (*line_ptr) {
1458 if (!display_in_cyl_units)
1459 i *= g_heads * g_sectors;
1473 absolute = 1000000000;
1482 bytes = (ullong) i * absolute;
1483 unit = sector_size * units_per_sector;
1484 bytes += unit/2; /* round */
1493 while (isdigit(*line_ptr)) {
1500 printf("Using default value %u\n", i);
1502 if (i >= low && i <= high)
1504 printf("Value is out of range\n");
1510 get_partition(int warn, int max)
1515 i = read_int(1, 0, max, 0, "Partition number") - 1;
1519 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1520 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1521 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1523 printf("Warning: partition %d has empty type\n", i+1);
1530 get_existing_partition(int warn, int max)
1535 for (i = 0; i < max; i++) {
1536 struct pte *pe = &ptes[i];
1537 struct partition *p = pe->part_table;
1539 if (p && !is_cleared_partition(p)) {
1546 printf("Selected partition %d\n", pno+1);
1549 printf("No partition is defined yet!\n");
1553 return get_partition(warn, max);
1557 get_nonexisting_partition(int warn, int max)
1562 for (i = 0; i < max; i++) {
1563 struct pte *pe = &ptes[i];
1564 struct partition *p = pe->part_table;
1566 if (p && is_cleared_partition(p)) {
1573 printf("Selected partition %d\n", pno+1);
1576 printf("All primary partitions have been defined already!\n");
1580 return get_partition(warn, max);
1587 display_in_cyl_units = !display_in_cyl_units;
1589 printf("Changing display/entry units to %s\n",
1594 toggle_active(int i)
1596 struct pte *pe = &ptes[i];
1597 struct partition *p = pe->part_table;
1599 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1600 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1601 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1606 toggle_dos_compatibility_flag(void)
1608 dos_compatible_flag = 1 - dos_compatible_flag;
1609 if (dos_compatible_flag) {
1610 sector_offset = g_sectors;
1611 printf("DOS Compatibility flag is set\n");
1614 printf("DOS Compatibility flag is not set\n");
1619 delete_partition(int i)
1621 struct pte *pe = &ptes[i];
1622 struct partition *p = pe->part_table;
1623 struct partition *q = pe->ext_pointer;
1625 /* Note that for the fifth partition (i == 4) we don't actually
1626 * decrement partitions.
1629 if (warn_geometry())
1630 return; /* C/H/S not set */
1634 sun_delete_partition(i);
1638 sgi_delete_partition(i);
1643 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1645 ptes[ext_index].ext_pointer = NULL;
1646 extended_offset = 0;
1652 if (!q->sys_ind && i > 4) {
1653 /* the last one in the chain - just delete */
1656 clear_partition(ptes[i].ext_pointer);
1657 ptes[i].changed = 1;
1659 /* not the last one - further ones will be moved down */
1661 /* delete this link in the chain */
1662 p = ptes[i-1].ext_pointer;
1664 set_start_sect(p, get_start_sect(q));
1665 set_nr_sects(p, get_nr_sects(q));
1666 ptes[i-1].changed = 1;
1667 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1668 /* the first logical in a longer chain */
1671 if (pe->part_table) /* prevent SEGFAULT */
1672 set_start_sect(pe->part_table,
1673 get_partition_start(pe) -
1675 pe->offset = extended_offset;
1679 if (g_partitions > 5) {
1681 while (i < g_partitions) {
1682 ptes[i] = ptes[i+1];
1686 /* the only logical: clear only */
1687 clear_partition(ptes[i].part_table);
1694 int i, sys, origsys;
1695 struct partition *p;
1697 /* If sgi_label then don't use get_existing_partition,
1698 let the user select a partition, since get_existing_partition()
1699 only works for Linux like partition tables. */
1700 if (!LABEL_IS_SGI) {
1701 i = get_existing_partition(0, g_partitions);
1703 i = get_partition(0, g_partitions);
1707 p = ptes[i].part_table;
1708 origsys = sys = get_sysid(i);
1710 /* if changing types T to 0 is allowed, then
1711 the reverse change must be allowed, too */
1712 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1713 printf("Partition %d does not exist yet!\n", i + 1);
1717 sys = read_hex(get_sys_types());
1719 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1720 printf("Type 0 means free space to many systems\n"
1721 "(but not to Linux). Having partitions of\n"
1722 "type 0 is probably unwise.\n");
1726 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1727 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1728 printf("You cannot change a partition into"
1729 " an extended one or vice versa\n");
1735 #if ENABLE_FEATURE_SUN_LABEL
1736 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1737 printf("Consider leaving partition 3 "
1738 "as Whole disk (5),\n"
1739 "as SunOS/Solaris expects it and "
1740 "even Linux likes it\n\n");
1742 #if ENABLE_FEATURE_SGI_LABEL
1745 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1746 (i == 8 && sys != 0)
1749 printf("Consider leaving partition 9 "
1750 "as volume header (0),\nand "
1751 "partition 11 as entire volume (6)"
1752 "as IRIX expects it\n\n");
1758 sun_change_sysid(i, sys);
1759 } else if (LABEL_IS_SGI) {
1760 sgi_change_sysid(i, sys);
1764 printf("Changed system type of partition %d "
1765 "to %x (%s)\n", i + 1, sys,
1766 partition_type(sys));
1767 ptes[i].changed = 1;
1768 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1774 #endif /* FEATURE_FDISK_WRITABLE */
1777 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1778 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1779 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1780 * Lubkin Oct. 1991). */
1783 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1785 int spc = g_heads * g_sectors;
1789 *h = ls / g_sectors;
1790 *s = ls % g_sectors + 1; /* sectors count from 1 */
1794 check_consistency(const struct partition *p, int partition)
1796 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1797 unsigned pec, peh, pes; /* physical ending c, h, s */
1798 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1799 unsigned lec, leh, les; /* logical ending c, h, s */
1801 if (!g_heads || !g_sectors || (partition >= 4))
1802 return; /* do not check extended partitions */
1804 /* physical beginning c, h, s */
1805 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1807 pbs = p->sector & 0x3f;
1809 /* physical ending c, h, s */
1810 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1812 pes = p->end_sector & 0x3f;
1814 /* compute logical beginning (c, h, s) */
1815 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1817 /* compute logical ending (c, h, s) */
1818 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1820 /* Same physical / logical beginning? */
1821 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1822 printf("Partition %d has different physical/logical "
1823 "beginnings (non-Linux?):\n", partition + 1);
1824 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1825 printf("logical=(%d, %d, %d)\n", lbc, lbh, lbs);
1828 /* Same physical / logical ending? */
1829 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1830 printf("Partition %d has different physical/logical "
1831 "endings:\n", partition + 1);
1832 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1833 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1836 /* Ending on cylinder boundary? */
1837 if (peh != (g_heads - 1) || pes != g_sectors) {
1838 printf("Partition %i does not end on cylinder boundary\n",
1844 list_disk_geometry(void)
1846 long long bytes = (total_number_of_sectors << 9);
1847 long megabytes = bytes/1000000;
1849 if (megabytes < 10000)
1850 printf("\nDisk %s: %ld MB, %lld bytes\n",
1851 disk_device, megabytes, bytes);
1853 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1854 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1855 printf("%d heads, %d sectors/track, %d cylinders",
1856 g_heads, g_sectors, g_cylinders);
1857 if (units_per_sector == 1)
1858 printf(", total %llu sectors",
1859 total_number_of_sectors / (sector_size/512));
1860 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1862 units_per_sector, sector_size, units_per_sector * sector_size);
1866 * Check whether partition entries are ordered by their starting positions.
1867 * Return 0 if OK. Return i if partition i should have been earlier.
1868 * Two separate checks: primary and logical partitions.
1871 wrong_p_order(int *prev)
1873 const struct pte *pe;
1874 const struct partition *p;
1875 ullong last_p_start_pos = 0, p_start_pos;
1878 for (i = 0; i < g_partitions; i++) {
1881 last_p_start_pos = 0;
1886 p_start_pos = get_partition_start(pe);
1888 if (last_p_start_pos > p_start_pos) {
1894 last_p_start_pos = p_start_pos;
1901 #if ENABLE_FEATURE_FDISK_ADVANCED
1903 * Fix the chain of logicals.
1904 * extended_offset is unchanged, the set of sectors used is unchanged
1905 * The chain is sorted so that sectors increase, and so that
1906 * starting sectors increase.
1908 * After this it may still be that cfdisk doesnt like the table.
1909 * (This is because cfdisk considers expanded parts, from link to
1910 * end of partition, and these may still overlap.)
1912 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1916 fix_chain_of_logicals(void)
1918 int j, oj, ojj, sj, sjj;
1919 struct partition *pj,*pjj,tmp;
1921 /* Stage 1: sort sectors but leave sector of part 4 */
1922 /* (Its sector is the global extended_offset.) */
1924 for (j = 5; j < g_partitions - 1; j++) {
1925 oj = ptes[j].offset;
1926 ojj = ptes[j+1].offset;
1928 ptes[j].offset = ojj;
1929 ptes[j+1].offset = oj;
1930 pj = ptes[j].part_table;
1931 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1932 pjj = ptes[j+1].part_table;
1933 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1934 set_start_sect(ptes[j-1].ext_pointer,
1935 ojj-extended_offset);
1936 set_start_sect(ptes[j].ext_pointer,
1937 oj-extended_offset);
1942 /* Stage 2: sort starting sectors */
1944 for (j = 4; j < g_partitions - 1; j++) {
1945 pj = ptes[j].part_table;
1946 pjj = ptes[j+1].part_table;
1947 sj = get_start_sect(pj);
1948 sjj = get_start_sect(pjj);
1949 oj = ptes[j].offset;
1950 ojj = ptes[j+1].offset;
1951 if (oj+sj > ojj+sjj) {
1955 set_start_sect(pj, ojj+sjj-oj);
1956 set_start_sect(pjj, oj+sj-ojj);
1961 /* Probably something was changed */
1962 for (j = 4; j < g_partitions; j++)
1963 ptes[j].changed = 1;
1968 fix_partition_table_order(void)
1970 struct pte *pei, *pek;
1973 if (!wrong_p_order(NULL)) {
1974 printf("Ordering is already correct\n\n");
1978 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1979 /* partition i should have come earlier, move it */
1980 /* We have to move data in the MBR */
1981 struct partition *pi, *pk, *pe, pbuf;
1985 pe = pei->ext_pointer;
1986 pei->ext_pointer = pek->ext_pointer;
1987 pek->ext_pointer = pe;
1989 pi = pei->part_table;
1990 pk = pek->part_table;
1992 memmove(&pbuf, pi, sizeof(struct partition));
1993 memmove(pi, pk, sizeof(struct partition));
1994 memmove(pk, &pbuf, sizeof(struct partition));
1996 pei->changed = pek->changed = 1;
2000 fix_chain_of_logicals();
2008 list_table(int xtra)
2010 const struct partition *p;
2014 sun_list_table(xtra);
2018 sgi_list_table(xtra);
2022 list_disk_geometry();
2025 xbsd_print_disklabel(xtra);
2029 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2030 but if the device name ends in a digit, say /dev/foo1,
2031 then the partition is called /dev/foo1p3. */
2032 w = strlen(disk_device);
2033 if (w && isdigit(disk_device[w-1]))
2038 // 1 12345678901 12345678901 12345678901 12
2039 printf("%*s Boot Start End Blocks Id System\n",
2042 for (i = 0; i < g_partitions; i++) {
2043 const struct pte *pe = &ptes[i];
2049 if (!p || is_cleared_partition(p))
2052 psects = get_nr_sects(p);
2056 if (sector_size < 1024) {
2057 pblocks /= (1024 / sector_size);
2058 podd = psects % (1024 / sector_size);
2060 if (sector_size > 1024)
2061 pblocks *= (sector_size / 1024);
2063 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2064 partname(disk_device, i+1, w+2),
2065 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2067 (ullong) cround(get_partition_start(pe)), /* start */
2068 (ullong) cround(get_partition_start(pe) + psects /* end */
2069 - (psects ? 1 : 0)),
2070 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2071 p->sys_ind, /* type id */
2072 partition_type(p->sys_ind)); /* type name */
2074 check_consistency(p, i);
2077 /* Is partition table in disk order? It need not be, but... */
2078 /* partition table entries are not checked for correct order if this
2079 is a sgi, sun or aix labeled disk... */
2080 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2082 printf("\nPartition table entries are not in disk order\n");
2086 #if ENABLE_FEATURE_FDISK_ADVANCED
2088 x_list_table(int extend)
2090 const struct pte *pe;
2091 const struct partition *p;
2094 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2095 disk_device, g_heads, g_sectors, g_cylinders);
2096 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2097 for (i = 0; i < g_partitions; i++) {
2099 p = (extend ? pe->ext_pointer : pe->part_table);
2101 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2102 i + 1, p->boot_ind, p->head,
2104 cylinder(p->sector, p->cyl), p->end_head,
2105 sector(p->end_sector),
2106 cylinder(p->end_sector, p->end_cyl),
2107 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2109 check_consistency(p, i);
2115 #if ENABLE_FEATURE_FDISK_WRITABLE
2117 fill_bounds(ullong *first, ullong *last)
2120 const struct pte *pe = &ptes[0];
2121 const struct partition *p;
2123 for (i = 0; i < g_partitions; pe++,i++) {
2125 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2126 first[i] = 0xffffffff;
2129 first[i] = get_partition_start(pe);
2130 last[i] = first[i] + get_nr_sects(p) - 1;
2136 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2138 ullong total, real_s, real_c;
2140 real_s = sector(s) - 1;
2141 real_c = cylinder(s, c);
2142 total = (real_c * g_sectors + real_s) * g_heads + h;
2144 printf("Partition %d contains sector 0\n", n);
2146 printf("Partition %d: head %d greater than maximum %d\n",
2148 if (real_s >= g_sectors)
2149 printf("Partition %d: sector %d greater than "
2150 "maximum %d\n", n, s, g_sectors);
2151 if (real_c >= g_cylinders)
2152 printf("Partition %d: cylinder %llu greater than "
2153 "maximum %d\n", n, real_c + 1, g_cylinders);
2154 if (g_cylinders <= 1024 && start != total)
2155 printf("Partition %d: previous sectors %llu disagrees with "
2156 "total %llu\n", n, start, total);
2164 ullong first[g_partitions], last[g_partitions];
2165 struct partition *p;
2167 if (warn_geometry())
2179 fill_bounds(first, last);
2180 for (i = 0; i < g_partitions; i++) {
2181 struct pte *pe = &ptes[i];
2184 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2185 check_consistency(p, i);
2186 if (get_partition_start(pe) < first[i])
2187 printf("Warning: bad start-of-data in "
2188 "partition %d\n", i + 1);
2189 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2191 total += last[i] + 1 - first[i];
2192 for (j = 0; j < i; j++) {
2193 if ((first[i] >= first[j] && first[i] <= last[j])
2194 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2195 printf("Warning: partition %d overlaps "
2196 "partition %d\n", j + 1, i + 1);
2197 total += first[i] >= first[j] ?
2198 first[i] : first[j];
2199 total -= last[i] <= last[j] ?
2206 if (extended_offset) {
2207 struct pte *pex = &ptes[ext_index];
2208 ullong e_last = get_start_sect(pex->part_table) +
2209 get_nr_sects(pex->part_table) - 1;
2211 for (i = 4; i < g_partitions; i++) {
2213 p = ptes[i].part_table;
2215 if (i != 4 || i + 1 < g_partitions)
2216 printf("Warning: partition %d "
2217 "is empty\n", i + 1);
2218 } else if (first[i] < extended_offset || last[i] > e_last) {
2219 printf("Logical partition %d not entirely in "
2220 "partition %d\n", i + 1, ext_index + 1);
2225 if (total > g_heads * g_sectors * g_cylinders)
2226 printf("Total allocated sectors %d greater than the maximum "
2227 "%d\n", total, g_heads * g_sectors * g_cylinders);
2229 total = g_heads * g_sectors * g_cylinders - total;
2231 printf("%d unallocated sectors\n", total);
2236 add_partition(int n, int sys)
2238 char mesg[256]; /* 48 does not suffice in Japanese */
2239 int i, num_read = 0;
2240 struct partition *p = ptes[n].part_table;
2241 struct partition *q = ptes[ext_index].part_table;
2243 ullong start, stop = 0;
2244 ullong first[g_partitions], last[g_partitions];
2246 if (p && p->sys_ind) {
2247 printf(msg_part_already_defined, n + 1);
2250 fill_bounds(first, last);
2252 start = sector_offset;
2253 if (display_in_cyl_units || !total_number_of_sectors)
2254 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2256 limit = total_number_of_sectors - 1;
2257 if (extended_offset) {
2258 first[ext_index] = extended_offset;
2259 last[ext_index] = get_start_sect(q) +
2260 get_nr_sects(q) - 1;
2263 start = extended_offset + sector_offset;
2264 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2266 if (display_in_cyl_units)
2267 for (i = 0; i < g_partitions; i++)
2268 first[i] = (cround(first[i]) - 1) * units_per_sector;
2270 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2273 for (i = 0; i < g_partitions; i++) {
2276 if (start == ptes[i].offset)
2277 start += sector_offset;
2278 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2279 if (start >= first[i] && start <= lastplusoff)
2280 start = lastplusoff + 1;
2284 if (start >= temp+units_per_sector && num_read) {
2285 printf("Sector %lld is already allocated\n", temp);
2289 if (!num_read && start == temp) {
2292 saved_start = start;
2293 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2295 if (display_in_cyl_units) {
2296 start = (start - 1) * units_per_sector;
2297 if (start < saved_start) start = saved_start;
2301 } while (start != temp || !num_read);
2302 if (n > 4) { /* NOT for fifth partition */
2303 struct pte *pe = &ptes[n];
2305 pe->offset = start - sector_offset;
2306 if (pe->offset == extended_offset) { /* must be corrected */
2308 if (sector_offset == 1)
2313 for (i = 0; i < g_partitions; i++) {
2314 struct pte *pe = &ptes[i];
2316 if (start < pe->offset && limit >= pe->offset)
2317 limit = pe->offset - 1;
2318 if (start < first[i] && limit >= first[i])
2319 limit = first[i] - 1;
2321 if (start > limit) {
2322 printf("No free sectors available\n");
2327 if (cround(start) == cround(limit)) {
2330 snprintf(mesg, sizeof(mesg),
2331 "Last %s or +size or +sizeM or +sizeK",
2332 str_units(SINGULAR));
2333 stop = read_int(cround(start), cround(limit), cround(limit),
2334 cround(start), mesg);
2335 if (display_in_cyl_units) {
2336 stop = stop * units_per_sector - 1;
2342 set_partition(n, 0, start, stop, sys);
2344 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2346 if (IS_EXTENDED(sys)) {
2347 struct pte *pe4 = &ptes[4];
2348 struct pte *pen = &ptes[n];
2351 pen->ext_pointer = p;
2352 pe4->offset = extended_offset = start;
2353 pe4->sectorbuffer = xzalloc(sector_size);
2354 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2355 pe4->ext_pointer = pe4->part_table + 1;
2364 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2365 struct pte *pe = &ptes[g_partitions];
2367 pe->sectorbuffer = xzalloc(sector_size);
2368 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2369 pe->ext_pointer = pe->part_table + 1;
2374 add_partition(g_partitions - 1, LINUX_NATIVE);
2380 int i, free_primary = 0;
2382 if (warn_geometry())
2386 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2390 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2394 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2395 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2396 "table first (use 'o'). This will destroy the present disk contents.\n");
2400 for (i = 0; i < 4; i++)
2401 free_primary += !ptes[i].part_table->sys_ind;
2403 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2404 printf("The maximum number of partitions has been created\n");
2408 if (!free_primary) {
2409 if (extended_offset)
2412 printf("You must delete some partition and add "
2413 "an extended partition first\n");
2416 snprintf(line, sizeof(line),
2419 " p primary partition (1-4)\n",
2421 "l logical (5 or over)" : "e extended"));
2423 c = read_nonempty(line);
2424 if (c == 'p' || c == 'P') {
2425 i = get_nonexisting_partition(0, 4);
2427 add_partition(i, LINUX_NATIVE);
2430 if (c == 'l' && extended_offset) {
2434 if (c == 'e' && !extended_offset) {
2435 i = get_nonexisting_partition(0, 4);
2437 add_partition(i, EXTENDED);
2440 printf("Invalid partition number "
2441 "for type '%c'\n", c);
2452 for (i = 0; i < 3; i++)
2453 if (ptes[i].changed)
2454 ptes[3].changed = 1;
2455 for (i = 3; i < g_partitions; i++) {
2456 struct pte *pe = &ptes[i];
2459 write_part_table_flag(pe->sectorbuffer);
2460 write_sector(pe->offset, pe->sectorbuffer);
2464 else if (LABEL_IS_SGI) {
2465 /* no test on change? the printf below might be mistaken */
2468 else if (LABEL_IS_SUN) {
2471 for (i = 0; i < 8; i++)
2472 if (ptes[i].changed)
2478 printf("The partition table has been altered!\n\n");
2479 reread_partition_table(1);
2483 reread_partition_table(int leave)
2487 printf("Calling ioctl() to re-read partition table\n");
2489 /* sleep(2); Huh? */
2490 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2491 "WARNING: rereading partition table "
2492 "failed, kernel still uses old table");
2496 "\nWARNING: If you have created or modified any DOS 6.x\n"
2497 "partitions, please see the fdisk manual page for additional\n"
2502 if (ENABLE_FEATURE_CLEAN_UP)
2507 #endif /* FEATURE_FDISK_WRITABLE */
2509 #if ENABLE_FEATURE_FDISK_ADVANCED
2510 #define MAX_PER_LINE 16
2512 print_buffer(char *pbuffer)
2516 for (i = 0, l = 0; i < sector_size; i++, l++) {
2518 printf("0x%03X:", i);
2519 printf(" %02X", (unsigned char) pbuffer[i]);
2520 if (l == MAX_PER_LINE - 1) {
2535 printf("Device: %s\n", disk_device);
2536 if (LABEL_IS_SGI || LABEL_IS_SUN)
2537 print_buffer(MBRbuffer);
2539 for (i = 3; i < g_partitions; i++)
2540 print_buffer(ptes[i].sectorbuffer);
2547 struct pte *pe = &ptes[i];
2548 struct partition *p = pe->part_table;
2551 if (warn_geometry())
2553 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2554 printf("Partition %d has no data area\n", i + 1);
2557 first = get_partition_start(pe);
2558 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2559 "New beginning of data") - pe->offset;
2561 if (new != get_nr_sects(p)) {
2562 first = get_nr_sects(p) + get_start_sect(p) - new;
2563 set_nr_sects(p, first);
2564 set_start_sect(p, new);
2576 c = tolower(read_nonempty("Expert command (m for help): "));
2584 move_begin(get_partition(0, g_partitions));
2587 user_cylinders = g_cylinders =
2588 read_int(1, g_cylinders, 1048576, 0,
2589 "Number of cylinders");
2591 sun_set_ncyl(g_cylinders);
2601 else if (LABEL_IS_SUN)
2603 else if (LABEL_IS_DOS)
2608 fix_partition_table_order();
2611 #if ENABLE_FEATURE_SGI_LABEL
2616 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2635 if (ENABLE_FEATURE_CLEAN_UP)
2642 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2643 "Number of sectors");
2644 if (dos_compatible_flag) {
2645 sector_offset = g_sectors;
2646 printf("Warning: setting sector offset for DOS "
2655 write_table(); /* does not return */
2659 sun_set_pcylcount();
2666 #endif /* ADVANCED mode */
2669 is_ide_cdrom_or_tape(const char *device)
2673 struct stat statbuf;
2676 /* No device was given explicitly, and we are trying some
2677 likely things. But opening /dev/hdc may produce errors like
2678 "hdc: tray open or drive not ready"
2679 if it happens to be a CD-ROM drive. It even happens that
2680 the process hangs on the attempt to read a music CD.
2681 So try to be careful. This only works since 2.1.73. */
2683 if (strncmp("/dev/hd", device, 7))
2686 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2687 procf = fopen_for_read(buf);
2688 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2689 is_ide = (!strncmp(buf, "cdrom", 5) ||
2690 !strncmp(buf, "tape", 4));
2692 /* Now when this proc file does not exist, skip the
2693 device when it is read-only. */
2694 if (stat(device, &statbuf) == 0)
2695 is_ide = ((statbuf.st_mode & 0222) == 0);
2704 open_list_and_close(const char *device, int user_specified)
2708 disk_device = device;
2709 if (setjmp(listingbuf))
2711 if (!user_specified)
2712 if (is_ide_cdrom_or_tape(device))
2715 /* Open disk_device, save file descriptor to dev_fd */
2717 gb = get_boot(TRY_ONLY);
2718 if (gb > 0) { /* I/O error */
2719 /* Ignore other errors, since we try IDE
2720 and SCSI hard disks which may not be
2721 installed on the system. */
2722 if (user_specified || errno == EACCES)
2723 bb_perror_msg("can't open '%s'", device);
2727 if (gb < 0) { /* no DOS signature */
2728 list_disk_geometry();
2731 #if ENABLE_FEATURE_OSF_LABEL
2732 if (bsd_trydev(device) < 0)
2734 printf("Disk %s doesn't contain a valid "
2735 "partition table\n", device);
2738 #if ENABLE_FEATURE_FDISK_WRITABLE
2739 if (!LABEL_IS_SUN && g_partitions > 4) {
2740 delete_partition(ext_index);
2748 /* for fdisk -l: try all things in /proc/partitions
2749 that look like a partition name (do not end in a digit) */
2751 list_devs_in_proc_partititons(void)
2754 char line[100], ptname[100], devname[120], *s;
2757 procpt = fopen_or_warn("/proc/partitions", "r");
2759 while (fgets(line, sizeof(line), procpt)) {
2760 if (sscanf(line, " %d %d %d %[^\n ]",
2761 &ma, &mi, &sz, ptname) != 4)
2763 for (s = ptname; *s; s++)
2767 sprintf(devname, "/dev/%s", ptname);
2768 open_list_and_close(devname, 0);
2770 #if ENABLE_FEATURE_CLEAN_UP
2775 #if ENABLE_FEATURE_FDISK_WRITABLE
2777 unknown_command(int c)
2779 printf("%c: unknown command\n", c);
2783 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2784 int fdisk_main(int argc, char **argv)
2789 * fdisk -l [-b sectorsize] [-u] device ...
2790 * fdisk -s [partition] ...
2791 * fdisk [-b sectorsize] [-u] device
2793 * Options -C, -H, -S set the geometry.
2797 close_dev_fd(); /* needed: fd 3 must not stay closed */
2799 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2800 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2801 §or_size, &user_cylinders, &user_heads, &user_sectors);
2804 if (opt & OPT_b) { // -b
2805 /* Ugly: this sector size is really per device,
2806 so cannot be combined with multiple disks,
2807 and the same goes for the C/H/S options.
2809 if (sector_size != 512 && sector_size != 1024
2810 && sector_size != 2048)
2813 user_set_sector_size = 1;
2815 if (user_heads <= 0 || user_heads >= 256)
2817 if (user_sectors <= 0 || user_sectors >= 64)
2820 display_in_cyl_units = 0; // -u
2822 #if ENABLE_FEATURE_FDISK_WRITABLE
2829 open_list_and_close(*argv, 1);
2832 /* we don't have device names, */
2833 /* use /proc/partitions instead */
2834 list_devs_in_proc_partititons();
2837 #if ENABLE_FEATURE_FDISK_WRITABLE
2841 #if ENABLE_FEATURE_FDISK_BLKSIZE
2848 for (j = 0; j < argc; j++) {
2849 unsigned long long size;
2850 fd = xopen(argv[j], O_RDONLY);
2851 size = bb_BLKGETSIZE_sectors(fd) / 2;
2854 printf("%lld\n", size);
2856 printf("%s: %lld\n", argv[j], size);
2862 #if ENABLE_FEATURE_FDISK_WRITABLE
2866 disk_device = argv[0];
2867 get_boot(OPEN_MAIN);
2870 /* OSF label, and no DOS label */
2871 printf("Detected an OSF/1 disklabel on %s, entering "
2872 "disklabel mode\n", disk_device);
2874 /*Why do we do this? It seems to be counter-intuitive*/
2875 current_label_type = LABEL_DOS;
2876 /* If we return we may want to make an empty DOS label? */
2882 c = tolower(read_nonempty("Command (m for help): "));
2886 toggle_active(get_partition(1, g_partitions));
2887 else if (LABEL_IS_SUN)
2888 toggle_sunflags(get_partition(1, g_partitions),
2890 else if (LABEL_IS_SGI)
2891 sgi_set_bootpartition(
2892 get_partition(1, g_partitions));
2898 printf("\nThe current boot file is: %s\n",
2899 sgi_get_bootfile());
2900 if (read_maybe_empty("Please enter the name of the "
2901 "new boot file: ") == '\n')
2902 printf("Boot file unchanged\n");
2904 sgi_set_bootfile(line_ptr);
2906 #if ENABLE_FEATURE_OSF_LABEL
2913 toggle_dos_compatibility_flag();
2914 else if (LABEL_IS_SUN)
2915 toggle_sunflags(get_partition(1, g_partitions),
2917 else if (LABEL_IS_SGI)
2918 sgi_set_swappartition(
2919 get_partition(1, g_partitions));
2926 /* If sgi_label then don't use get_existing_partition,
2927 let the user select a partition, since
2928 get_existing_partition() only works for Linux-like
2930 if (!LABEL_IS_SGI) {
2931 j = get_existing_partition(1, g_partitions);
2933 j = get_partition(1, g_partitions);
2936 delete_partition(j);
2945 list_types(get_sys_types());
2960 if (ENABLE_FEATURE_CLEAN_UP)
2965 #if ENABLE_FEATURE_SUN_LABEL
2979 write_table(); /* does not return */
2981 #if ENABLE_FEATURE_FDISK_ADVANCED
2984 printf("\n\tSorry, no experts menu for SGI "
2985 "partition tables available\n\n");
2996 #endif /* FEATURE_FDISK_WRITABLE */