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
47 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
51 /* Used for sector numbers. Today's disk sizes make it necessary */
52 typedef unsigned long long ullong;
56 unsigned char sectors;
57 unsigned short cylinders;
61 #define HDIO_GETGEO 0x0301 /* get device geometry */
63 static const char msg_building_new_label[] ALIGN1 =
64 "Building a new %s. Changes will remain in memory only,\n"
65 "until you decide to write them. After that the previous content\n"
66 "won't be recoverable.\n\n";
68 static const char msg_part_already_defined[] ALIGN1 =
69 "Partition %d is already defined, delete it before re-adding\n";
73 unsigned char boot_ind; /* 0x80 - active */
74 unsigned char head; /* starting head */
75 unsigned char sector; /* starting sector */
76 unsigned char cyl; /* starting cylinder */
77 unsigned char sys_ind; /* What partition type */
78 unsigned char end_head; /* end head */
79 unsigned char end_sector; /* end sector */
80 unsigned char end_cyl; /* end cylinder */
81 unsigned char start4[4]; /* starting sector counting from 0 */
82 unsigned char size4[4]; /* nr of sectors in partition */
85 static const char unable_to_open[] ALIGN1 = "cannot open %s";
86 static const char unable_to_read[] ALIGN1 = "cannot read from %s";
87 static const char unable_to_seek[] ALIGN1 = "cannot seek on %s";
88 static const char unable_to_write[] ALIGN1 = "cannot write to %s";
89 static const char ioctl_error[] ALIGN1 = "BLKGETSIZE ioctl failed on %s";
90 static void fdisk_fatal(const char *why) ATTRIBUTE_NORETURN;
93 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
96 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
98 #if ENABLE_FEATURE_SUN_LABEL
99 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
100 #define STATIC_SUN static
102 #define LABEL_IS_SUN 0
103 #define STATIC_SUN extern
106 #if ENABLE_FEATURE_SGI_LABEL
107 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
108 #define STATIC_SGI static
110 #define LABEL_IS_SGI 0
111 #define STATIC_SGI extern
114 #if ENABLE_FEATURE_AIX_LABEL
115 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
116 #define STATIC_AIX static
118 #define LABEL_IS_AIX 0
119 #define STATIC_AIX extern
122 #if ENABLE_FEATURE_OSF_LABEL
123 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
124 #define STATIC_OSF static
126 #define LABEL_IS_OSF 0
127 #define STATIC_OSF extern
130 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
132 static void update_units(void);
133 #if ENABLE_FEATURE_FDISK_WRITABLE
134 static void change_units(void);
135 static void reread_partition_table(int leave);
136 static void delete_partition(int i);
137 static int get_partition(int warn, int max);
138 static void list_types(const char *const *sys);
139 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
141 static const char *partition_type(unsigned char type);
142 static void get_geometry(void);
143 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
144 static int get_boot(enum action what);
146 static int get_boot(void);
152 static unsigned get_start_sect(const struct partition *p);
153 static unsigned get_nr_sects(const struct partition *p);
156 * per partition table entry data
158 * The four primary partitions have the same sectorbuffer (MBRbuffer)
159 * and have NULL ext_pointer.
160 * Each logical partition table entry has two pointers, one for the
161 * partition and one link to the next one.
164 struct partition *part_table; /* points into sectorbuffer */
165 struct partition *ext_pointer; /* points into sectorbuffer */
166 ullong offset; /* disk sector number */
167 char *sectorbuffer; /* disk sector contents */
168 #if ENABLE_FEATURE_FDISK_WRITABLE
169 char changed; /* boolean */
173 /* DOS partition types */
175 static const char *const i386_sys_types[] = {
179 "\x05" "Extended", /* DOS 3.3+ extended partition */
180 "\x06" "FAT16", /* DOS 16-bit >=32M */
181 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
182 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
183 "\x0b" "Win95 FAT32",
184 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
185 "\x0e" "Win95 FAT16 (LBA)",
186 "\x0f" "Win95 Ext'd (LBA)",
187 "\x11" "Hidden FAT12",
188 "\x12" "Compaq diagnostics",
189 "\x14" "Hidden FAT16 <32M",
190 "\x16" "Hidden FAT16",
191 "\x17" "Hidden HPFS/NTFS",
192 "\x1b" "Hidden Win95 FAT32",
193 "\x1c" "Hidden W95 FAT32 (LBA)",
194 "\x1e" "Hidden W95 FAT16 (LBA)",
195 "\x3c" "Part.Magic recovery",
196 "\x41" "PPC PReP Boot",
198 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
199 "\x80" "Old Minix", /* Minix 1.4a and earlier */
200 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
201 "\x82" "Linux swap", /* also Solaris */
203 "\x84" "OS/2 hidden C: drive",
204 "\x85" "Linux extended",
205 "\x86" "NTFS volume set",
206 "\x87" "NTFS volume set",
208 "\x9f" "BSD/OS", /* BSDI */
209 "\xa0" "Thinkpad hibernation",
210 "\xa5" "FreeBSD", /* various BSD flavours */
214 "\xab" "Darwin boot",
217 "\xbe" "Solaris boot",
219 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
220 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
221 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
222 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
223 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
224 autodetect using persistent
226 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
229 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
230 "\x09" "AIX bootable", /* AIX data or Coherent */
232 "\x18" "AST SmartSleep",
235 "\x40" "Venix 80286",
237 "\x4e" "QNX4.x 2nd part",
238 "\x4f" "QNX4.x 3rd part",
240 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
241 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
242 "\x53" "OnTrack DM6 Aux3",
246 "\x5c" "Priam Edisk",
248 "\x64" "Novell Netware 286",
249 "\x65" "Novell Netware 386",
250 "\x70" "DiskSecure Multi-Boot",
253 "\x94" "Amoeba BBT", /* (bad block table) */
255 "\xbb" "Boot Wizard hidden",
256 "\xc1" "DRDOS/sec (FAT-12)",
257 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
258 "\xc6" "DRDOS/sec (FAT-16)",
260 "\xda" "Non-FS data",
261 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
262 Concurrent DOS or CTOS */
263 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
264 "\xdf" "BootIt", /* BootIt EMBRM */
265 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
266 extended partition */
267 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
268 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
269 partition < 1024 cyl. */
271 "\xf4" "SpeedStor", /* SpeedStor large partition */
272 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
273 "\xff" "BBT", /* Xenix Bad Block Table */
279 dev_fd = 3 /* the disk */
286 const char *disk_device;
287 int g_partitions; // = 4; /* maximum partition + 1 */
288 unsigned units_per_sector; // = 1;
289 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
290 unsigned user_set_sector_size;
291 unsigned sector_offset; // = 1;
292 unsigned g_heads, g_sectors, g_cylinders;
293 enum label_type current_label_type;
294 smallint display_in_cyl_units; // = 1;
295 #if ENABLE_FEATURE_OSF_LABEL
296 smallint possibly_osf_label;
300 char line_buffer[80];
301 char partname_buffer[80];
302 /* Raw disk label. For DOS-type partition tables the MBR,
303 * with descriptions of the primary partitions. */
304 char MBRbuffer[MAX_SECTOR_SIZE];
305 /* Partition tables */
306 struct pte ptes[MAXIMUM_PARTS];
308 #define G (*ptr_to_globals)
309 #define line_ptr (G.line_ptr)
310 #define disk_device (G.disk_device )
311 #define g_partitions (G.g_partitions )
312 #define units_per_sector (G.units_per_sector )
313 #define sector_size (G.sector_size )
314 #define user_set_sector_size (G.user_set_sector_size)
315 #define sector_offset (G.sector_offset )
316 #define g_heads (G.g_heads )
317 #define g_sectors (G.g_sectors )
318 #define g_cylinders (G.g_cylinders )
319 #define current_label_type (G.current_label_type )
320 #define display_in_cyl_units (G.display_in_cyl_units)
321 #define possibly_osf_label (G.possibly_osf_label )
322 #define listingbuf (G.listingbuf)
323 #define line_buffer (G.line_buffer)
324 #define partname_buffer (G.partname_buffer)
325 #define MBRbuffer (G.MBRbuffer)
326 #define ptes (G.ptes)
327 #define INIT_G() do { \
328 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
329 sector_size = DEFAULT_SECTOR_SIZE; \
332 display_in_cyl_units = 1; \
333 units_per_sector = 1; \
337 /* TODO: move to libbb? */
338 static ullong bb_BLKGETSIZE_sectors(int fd)
341 unsigned long longsectors;
343 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
344 /* got bytes, convert to 512 byte sectors */
347 /* Needs temp of type long */
348 if (ioctl(fd, BLKGETSIZE, &longsectors))
354 #define IS_EXTENDED(i) \
355 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
357 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
359 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
361 #define pt_offset(b, n) \
362 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
364 #define sector(s) ((s) & 0x3f)
366 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
368 #define hsc2sector(h,s,c) \
369 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
371 #define set_hsc(h,s,c,sector) \
373 s = sector % g_sectors + 1; \
374 sector /= g_sectors; \
375 h = sector % g_heads; \
378 s |= (sector >> 2) & 0xc0; \
384 /* Not really closing, but making sure it is open, and to harmless place */
385 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
388 #if ENABLE_FEATURE_FDISK_WRITABLE
389 /* read line; return 0 or first printable char */
391 read_line(const char *prompt)
395 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
397 exit(0); /* Ctrl-D or Ctrl-C */
399 if (line_buffer[sz-1] == '\n')
400 line_buffer[--sz] = '\0';
402 line_ptr = line_buffer;
403 while (*line_ptr && !isgraph(*line_ptr))
410 * return partition name - uses static storage
413 partname(const char *dev, int pno, int lth)
420 bufp = partname_buffer;
421 bufsiz = sizeof(partname_buffer);
426 if (isdigit(dev[w-1]))
429 /* devfs kludge - note: fdisk partition names are not supposed
430 to equal kernel names, so there is no reason to do this */
431 if (strcmp(dev + w - 4, "disc") == 0) {
439 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
440 lth-wp-2, w, dev, p, pno);
442 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
447 #if ENABLE_FEATURE_FDISK_WRITABLE
449 set_all_unchanged(void)
453 for (i = 0; i < MAXIMUM_PARTS; i++)
457 static ALWAYS_INLINE void
462 #endif /* FEATURE_FDISK_WRITABLE */
464 static ALWAYS_INLINE struct partition *
465 get_part_table(int i)
467 return ptes[i].part_table;
472 { /* n==1: use singular */
474 return display_in_cyl_units ? "cylinder" : "sector";
475 return display_in_cyl_units ? "cylinders" : "sectors";
479 valid_part_table_flag(const char *mbuffer)
481 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
484 #if ENABLE_FEATURE_FDISK_WRITABLE
485 static ALWAYS_INLINE void
486 write_part_table_flag(char *b)
493 read_nonempty(const char *mesg)
495 while (!read_line(mesg)) /* repeat */;
500 read_maybe_empty(const char *mesg)
502 if (!read_line(mesg)) {
503 line_ptr = line_buffer;
511 read_hex(const char *const *sys)
515 read_nonempty("Hex code (type L to list codes): ");
516 if (*line_ptr == 'l' || *line_ptr == 'L') {
520 v = bb_strtoul(line_ptr, NULL, 16);
522 /* Bad input also triggers this */
527 #endif /* FEATURE_FDISK_WRITABLE */
529 #include "fdisk_aix.c"
532 unsigned char info[128]; /* Informative text string */
533 unsigned char spare0[14];
535 unsigned char spare1;
537 unsigned char spare2;
540 unsigned char spare1[246]; /* Boot information etc. */
541 unsigned short rspeed; /* Disk rotational speed */
542 unsigned short pcylcount; /* Physical cylinder count */
543 unsigned short sparecyl; /* extra sects per cylinder */
544 unsigned char spare2[4]; /* More magic... */
545 unsigned short ilfact; /* Interleave factor */
546 unsigned short ncyl; /* Data cylinder count */
547 unsigned short nacyl; /* Alt. cylinder count */
548 unsigned short ntrks; /* Tracks per cylinder */
549 unsigned short nsect; /* Sectors per track */
550 unsigned char spare3[4]; /* Even more magic... */
551 struct sun_partinfo {
552 uint32_t start_cylinder;
553 uint32_t num_sectors;
555 unsigned short magic; /* Magic number */
556 unsigned short csum; /* Label xor'd checksum */
558 #define sunlabel ((sun_partition *)MBRbuffer)
559 STATIC_OSF void bsd_select(void);
560 STATIC_OSF void xbsd_print_disklabel(int);
561 #include "fdisk_osf.c"
563 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
565 fdisk_swap16(uint16_t x)
567 return (x << 8) | (x >> 8);
571 fdisk_swap32(uint32_t x)
574 ((x & 0xFF00) << 8) |
575 ((x & 0xFF0000) >> 8) |
580 STATIC_SGI const char *const sgi_sys_types[];
581 STATIC_SGI unsigned sgi_get_num_sectors(int i);
582 STATIC_SGI int sgi_get_sysid(int i);
583 STATIC_SGI void sgi_delete_partition(int i);
584 STATIC_SGI void sgi_change_sysid(int i, int sys);
585 STATIC_SGI void sgi_list_table(int xtra);
586 #if ENABLE_FEATURE_FDISK_ADVANCED
587 STATIC_SGI void sgi_set_xcyl(void);
589 STATIC_SGI int verify_sgi(int verbose);
590 STATIC_SGI void sgi_add_partition(int n, int sys);
591 STATIC_SGI void sgi_set_swappartition(int i);
592 STATIC_SGI const char *sgi_get_bootfile(void);
593 STATIC_SGI void sgi_set_bootfile(const char* aFile);
594 STATIC_SGI void create_sgiinfo(void);
595 STATIC_SGI void sgi_write_table(void);
596 STATIC_SGI void sgi_set_bootpartition(int i);
597 #include "fdisk_sgi.c"
599 STATIC_SUN const char *const sun_sys_types[];
600 STATIC_SUN void sun_delete_partition(int i);
601 STATIC_SUN void sun_change_sysid(int i, int sys);
602 STATIC_SUN void sun_list_table(int xtra);
603 STATIC_SUN void add_sun_partition(int n, int sys);
604 #if ENABLE_FEATURE_FDISK_ADVANCED
605 STATIC_SUN void sun_set_alt_cyl(void);
606 STATIC_SUN void sun_set_ncyl(int cyl);
607 STATIC_SUN void sun_set_xcyl(void);
608 STATIC_SUN void sun_set_ilfact(void);
609 STATIC_SUN void sun_set_rspeed(void);
610 STATIC_SUN void sun_set_pcylcount(void);
612 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
613 STATIC_SUN void verify_sun(void);
614 STATIC_SUN void sun_write_table(void);
615 #include "fdisk_sun.c"
617 #if ENABLE_FEATURE_FDISK_WRITABLE
618 /* start_sect and nr_sects are stored little endian on all machines */
619 /* moreover, they are not aligned correctly */
621 store4_little_endian(unsigned char *cp, unsigned val)
628 #endif /* FEATURE_FDISK_WRITABLE */
631 read4_little_endian(const unsigned char *cp)
633 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
636 #if ENABLE_FEATURE_FDISK_WRITABLE
638 set_start_sect(struct partition *p, unsigned start_sect)
640 store4_little_endian(p->start4, start_sect);
645 get_start_sect(const struct partition *p)
647 return read4_little_endian(p->start4);
650 #if ENABLE_FEATURE_FDISK_WRITABLE
652 set_nr_sects(struct partition *p, unsigned nr_sects)
654 store4_little_endian(p->size4, nr_sects);
659 get_nr_sects(const struct partition *p)
661 return read4_little_endian(p->size4);
664 static int ext_index; /* the prime extended partition */
665 static smallint listing; /* no aborts for fdisk -l */
666 static smallint dos_compatible_flag = 1;
667 #if ENABLE_FEATURE_FDISK_WRITABLE
668 //static int dos_changed;
669 static smallint nowarn; /* no warnings for fdisk -l/-s */
672 static unsigned user_cylinders, user_heads, user_sectors;
673 static unsigned pt_heads, pt_sectors;
674 static unsigned kern_heads, kern_sectors;
676 static ullong extended_offset; /* offset of link pointers */
677 static ullong total_number_of_sectors;
679 static void fdisk_fatal(const char *why)
683 longjmp(listingbuf, 1);
685 bb_error_msg_and_die(why, disk_device);
689 seek_sector(ullong secno)
691 secno *= sector_size;
692 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
693 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
694 fdisk_fatal(unable_to_seek);
696 if (secno > MAXINT(off_t)
697 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
699 fdisk_fatal(unable_to_seek);
704 #if ENABLE_FEATURE_FDISK_WRITABLE
706 write_sector(ullong secno, char *buf)
709 if (write(dev_fd, buf, sector_size) != sector_size)
710 fdisk_fatal(unable_to_write);
714 /* Allocate a buffer and read a partition table sector */
716 read_pte(struct pte *pe, ullong offset)
719 pe->sectorbuffer = xmalloc(sector_size);
721 if (read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
722 fdisk_fatal(unable_to_read);
723 #if ENABLE_FEATURE_FDISK_WRITABLE
726 pe->part_table = pe->ext_pointer = NULL;
730 get_partition_start(const struct pte *pe)
732 return pe->offset + get_start_sect(pe->part_table);
735 #if ENABLE_FEATURE_FDISK_WRITABLE
737 * Avoid warning about DOS partitions when no DOS partition was changed.
738 * Here a heuristic "is probably dos partition".
739 * We might also do the opposite and warn in all cases except
740 * for "is probably nondos partition".
744 is_dos_partition(int t)
746 return (t == 1 || t == 4 || t == 6 ||
747 t == 0x0b || t == 0x0c || t == 0x0e ||
748 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
749 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
750 t == 0xc1 || t == 0xc4 || t == 0xc6);
757 puts("Command Action");
759 puts("a\ttoggle a read only flag"); /* sun */
760 puts("b\tedit bsd disklabel");
761 puts("c\ttoggle the mountable flag"); /* sun */
762 puts("d\tdelete a partition");
763 puts("l\tlist known partition types");
764 puts("n\tadd a new partition");
765 puts("o\tcreate a new empty DOS partition table");
766 puts("p\tprint the partition table");
767 puts("q\tquit without saving changes");
768 puts("s\tcreate a new empty Sun disklabel"); /* sun */
769 puts("t\tchange a partition's system id");
770 puts("u\tchange display/entry units");
771 puts("v\tverify the partition table");
772 puts("w\twrite table to disk and exit");
773 #if ENABLE_FEATURE_FDISK_ADVANCED
774 puts("x\textra functionality (experts only)");
776 } else if (LABEL_IS_SGI) {
777 puts("a\tselect bootable partition"); /* sgi flavour */
778 puts("b\tedit bootfile entry"); /* sgi */
779 puts("c\tselect sgi swap partition"); /* sgi flavour */
780 puts("d\tdelete a partition");
781 puts("l\tlist known partition types");
782 puts("n\tadd a new partition");
783 puts("o\tcreate a new empty DOS partition table");
784 puts("p\tprint the partition table");
785 puts("q\tquit without saving changes");
786 puts("s\tcreate a new empty Sun disklabel"); /* sun */
787 puts("t\tchange a partition's system id");
788 puts("u\tchange display/entry units");
789 puts("v\tverify the partition table");
790 puts("w\twrite table to disk and exit");
791 } else if (LABEL_IS_AIX) {
792 puts("o\tcreate a new empty DOS partition table");
793 puts("q\tquit without saving changes");
794 puts("s\tcreate a new empty Sun disklabel"); /* sun */
796 puts("a\ttoggle a bootable flag");
797 puts("b\tedit bsd disklabel");
798 puts("c\ttoggle the dos compatibility flag");
799 puts("d\tdelete a partition");
800 puts("l\tlist known partition types");
801 puts("n\tadd a new partition");
802 puts("o\tcreate a new empty DOS partition table");
803 puts("p\tprint the partition table");
804 puts("q\tquit without saving changes");
805 puts("s\tcreate a new empty Sun disklabel"); /* sun */
806 puts("t\tchange a partition's system id");
807 puts("u\tchange display/entry units");
808 puts("v\tverify the partition table");
809 puts("w\twrite table to disk and exit");
810 #if ENABLE_FEATURE_FDISK_ADVANCED
811 puts("x\textra functionality (experts only)");
815 #endif /* FEATURE_FDISK_WRITABLE */
818 #if ENABLE_FEATURE_FDISK_ADVANCED
822 puts("Command Action");
824 puts("a\tchange number of alternate cylinders"); /*sun*/
825 puts("c\tchange number of cylinders");
826 puts("d\tprint the raw data in the partition table");
827 puts("e\tchange number of extra sectors per cylinder");/*sun*/
828 puts("h\tchange number of heads");
829 puts("i\tchange interleave factor"); /*sun*/
830 puts("o\tchange rotation speed (rpm)"); /*sun*/
831 puts("p\tprint the partition table");
832 puts("q\tquit without saving changes");
833 puts("r\treturn to main menu");
834 puts("s\tchange number of sectors/track");
835 puts("v\tverify the partition table");
836 puts("w\twrite table to disk and exit");
837 puts("y\tchange number of physical cylinders"); /*sun*/
838 } else if (LABEL_IS_SGI) {
839 puts("b\tmove beginning of data in a partition"); /* !sun */
840 puts("c\tchange number of cylinders");
841 puts("d\tprint the raw data in the partition table");
842 puts("e\tlist extended partitions"); /* !sun */
843 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
844 puts("h\tchange number of heads");
845 puts("p\tprint the partition table");
846 puts("q\tquit without saving changes");
847 puts("r\treturn to main menu");
848 puts("s\tchange number of sectors/track");
849 puts("v\tverify the partition table");
850 puts("w\twrite table to disk and exit");
851 } else if (LABEL_IS_AIX) {
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");
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("f\tfix partition order"); /* !sun, !aix, !sgi */
870 #if ENABLE_FEATURE_SGI_LABEL
871 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
873 puts("h\tchange number of heads");
874 puts("p\tprint the partition table");
875 puts("q\tquit without saving changes");
876 puts("r\treturn to main menu");
877 puts("s\tchange number of sectors/track");
878 puts("v\tverify the partition table");
879 puts("w\twrite table to disk and exit");
882 #endif /* ADVANCED mode */
884 #if ENABLE_FEATURE_FDISK_WRITABLE
885 static const char *const *
889 LABEL_IS_SUN ? sun_sys_types :
890 LABEL_IS_SGI ? sgi_sys_types :
894 #define get_sys_types() i386_sys_types
895 #endif /* FEATURE_FDISK_WRITABLE */
898 partition_type(unsigned char type)
901 const char *const *types = get_sys_types();
903 for (i = 0; types[i]; i++)
904 if ((unsigned char)types[i][0] == type)
911 #if ENABLE_FEATURE_FDISK_WRITABLE
915 return LABEL_IS_SUN ? sunlabel->infos[i].id :
916 (LABEL_IS_SGI ? sgi_get_sysid(i) :
917 ptes[i].part_table->sys_ind);
921 list_types(const char *const *sys)
926 unsigned done, next, size;
929 for (size = 0; sys[size]; size++) /* */;
932 for (i = COLS-1; i >= 0; i--) {
933 done += (size + i - done) / (i + 1);
934 last[COLS-1 - i] = done;
939 printf("%c%2x %-22.22s", i ? ' ' : '\n',
940 (unsigned char)sys[next][0],
942 next = last[i++] + done;
943 if (i >= COLS || next >= last[i]) {
947 } while (done < last[0]);
950 #endif /* FEATURE_FDISK_WRITABLE */
953 is_cleared_partition(const struct partition *p)
955 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
956 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
957 get_start_sect(p) || get_nr_sects(p));
961 clear_partition(struct partition *p)
965 memset(p, 0, sizeof(struct partition));
968 #if ENABLE_FEATURE_FDISK_WRITABLE
970 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
976 p = ptes[i].ext_pointer;
977 offset = extended_offset;
979 p = ptes[i].part_table;
980 offset = ptes[i].offset;
984 set_start_sect(p, start - offset);
985 set_nr_sects(p, stop - start + 1);
986 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
987 start = g_heads * g_sectors * 1024 - 1;
988 set_hsc(p->head, p->sector, p->cyl, start);
989 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
990 stop = g_heads * g_sectors * 1024 - 1;
991 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
999 if (g_heads && g_sectors && g_cylinders)
1002 printf("Unknown value(s) for:");
1008 printf(" cylinders");
1010 #if ENABLE_FEATURE_FDISK_WRITABLE
1011 " (settable in the extra functions menu)"
1020 int cyl_units = g_heads * g_sectors;
1022 if (display_in_cyl_units && cyl_units)
1023 units_per_sector = cyl_units;
1025 units_per_sector = 1; /* in sectors */
1028 #if ENABLE_FEATURE_FDISK_WRITABLE
1030 warn_cylinders(void)
1032 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1034 "The number of cylinders for this disk is set to %d.\n"
1035 "There is nothing wrong with that, but this is larger than 1024,\n"
1036 "and could in certain setups cause problems with:\n"
1037 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1038 "2) booting and partitioning software from other OSs\n"
1039 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1045 read_extended(int ext)
1049 struct partition *p, *q;
1053 pex->ext_pointer = pex->part_table;
1055 p = pex->part_table;
1056 if (!get_start_sect(p)) {
1057 printf("Bad offset in primary extended partition\n");
1061 while (IS_EXTENDED(p->sys_ind)) {
1062 struct pte *pe = &ptes[g_partitions];
1064 if (g_partitions >= MAXIMUM_PARTS) {
1065 /* This is not a Linux restriction, but
1066 this program uses arrays of size MAXIMUM_PARTS.
1067 Do not try to 'improve' this test. */
1068 struct pte *pre = &ptes[g_partitions - 1];
1069 #if ENABLE_FEATURE_FDISK_WRITABLE
1070 printf("Warning: deleting partitions after %d\n",
1074 clear_partition(pre->ext_pointer);
1078 read_pte(pe, extended_offset + get_start_sect(p));
1080 if (!extended_offset)
1081 extended_offset = get_start_sect(p);
1083 q = p = pt_offset(pe->sectorbuffer, 0);
1084 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1085 if (IS_EXTENDED(p->sys_ind)) {
1086 if (pe->ext_pointer)
1087 printf("Warning: extra link "
1088 "pointer in partition table"
1089 " %d\n", g_partitions + 1);
1091 pe->ext_pointer = p;
1092 } else if (p->sys_ind) {
1094 printf("Warning: ignoring extra "
1095 "data in partition table"
1096 " %d\n", g_partitions + 1);
1102 /* very strange code here... */
1103 if (!pe->part_table) {
1104 if (q != pe->ext_pointer)
1107 pe->part_table = q + 1;
1109 if (!pe->ext_pointer) {
1110 if (q != pe->part_table)
1111 pe->ext_pointer = q;
1113 pe->ext_pointer = q + 1;
1116 p = pe->ext_pointer;
1120 #if ENABLE_FEATURE_FDISK_WRITABLE
1121 /* remove empty links */
1123 for (i = 4; i < g_partitions; i++) {
1124 struct pte *pe = &ptes[i];
1126 if (!get_nr_sects(pe->part_table)
1127 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1129 printf("Omitting empty partition (%d)\n", i+1);
1130 delete_partition(i);
1131 goto remove; /* numbering changed */
1137 #if ENABLE_FEATURE_FDISK_WRITABLE
1139 create_doslabel(void)
1143 printf(msg_building_new_label, "DOS disklabel");
1145 current_label_type = LABEL_DOS;
1147 #if ENABLE_FEATURE_OSF_LABEL
1148 possibly_osf_label = 0;
1152 for (i = 510-64; i < 510; i++)
1154 write_part_table_flag(MBRbuffer);
1155 extended_offset = 0;
1156 set_all_unchanged();
1158 get_boot(CREATE_EMPTY_DOS);
1160 #endif /* FEATURE_FDISK_WRITABLE */
1163 get_sectorsize(void)
1165 if (!user_set_sector_size) {
1167 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1169 if (sector_size != DEFAULT_SECTOR_SIZE)
1170 printf("Note: sector size is %d (not %d)\n",
1171 sector_size, DEFAULT_SECTOR_SIZE);
1176 get_kernel_geometry(void)
1178 struct hd_geometry geometry;
1180 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1181 kern_heads = geometry.heads;
1182 kern_sectors = geometry.sectors;
1183 /* never use geometry.cylinders - it is truncated */
1188 get_partition_table_geometry(void)
1190 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1191 struct partition *p;
1192 int i, h, s, hh, ss;
1196 if (!(valid_part_table_flag((char*)bufp)))
1200 for (i = 0; i < 4; i++) {
1201 p = pt_offset(bufp, i);
1202 if (p->sys_ind != 0) {
1203 h = p->end_head + 1;
1204 s = (p->end_sector & 077);
1209 } else if (hh != h || ss != s)
1214 if (!first && !bad) {
1226 sec_fac = sector_size / 512;
1227 #if ENABLE_FEATURE_SUN_LABEL
1228 guess_device_type();
1230 g_heads = g_cylinders = g_sectors = 0;
1231 kern_heads = kern_sectors = 0;
1232 pt_heads = pt_sectors = 0;
1234 get_kernel_geometry();
1235 get_partition_table_geometry();
1237 g_heads = user_heads ? user_heads :
1238 pt_heads ? pt_heads :
1239 kern_heads ? kern_heads : 255;
1240 g_sectors = user_sectors ? user_sectors :
1241 pt_sectors ? pt_sectors :
1242 kern_sectors ? kern_sectors : 63;
1243 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1246 if (dos_compatible_flag)
1247 sector_offset = g_sectors;
1249 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1251 g_cylinders = user_cylinders;
1255 * Opens disk_device and optionally reads MBR.
1256 * FIXME: document what each 'what' value will do!
1258 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1259 * 0: found or created label
1262 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1263 static int get_boot(enum action what)
1265 static int get_boot(void)
1266 #define get_boot(what) get_boot()
1272 for (i = 0; i < 4; i++) {
1273 struct pte *pe = &ptes[i];
1274 pe->part_table = pt_offset(MBRbuffer, i);
1275 pe->ext_pointer = NULL;
1277 pe->sectorbuffer = MBRbuffer;
1278 #if ENABLE_FEATURE_FDISK_WRITABLE
1279 pe->changed = (what == CREATE_EMPTY_DOS);
1283 #if ENABLE_FEATURE_FDISK_WRITABLE
1284 // ALERT! highly idiotic design!
1285 // We end up here when we call get_boot() recursively
1286 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1287 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1288 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1289 // So skip opening device _again_...
1290 if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1293 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1296 fd = open(disk_device, O_RDONLY);
1298 if (what == TRY_ONLY)
1300 fdisk_fatal(unable_to_open);
1302 printf("'%s' is opened for read only\n", disk_device);
1304 xmove_fd(fd, dev_fd);
1305 if (512 != read(dev_fd, MBRbuffer, 512)) {
1306 if (what == TRY_ONLY) {
1310 fdisk_fatal(unable_to_read);
1313 fd = open(disk_device, O_RDONLY);
1316 if (512 != read(fd, MBRbuffer, 512)) {
1320 xmove_fd(fd, dev_fd);
1326 #if ENABLE_FEATURE_SUN_LABEL
1327 if (check_sun_label())
1330 #if ENABLE_FEATURE_SGI_LABEL
1331 if (check_sgi_label())
1334 #if ENABLE_FEATURE_AIX_LABEL
1335 if (check_aix_label())
1338 #if ENABLE_FEATURE_OSF_LABEL
1339 if (check_osf_label()) {
1340 possibly_osf_label = 1;
1341 if (!valid_part_table_flag(MBRbuffer)) {
1342 current_label_type = LABEL_OSF;
1345 printf("This disk has both DOS and BSD magic.\n"
1346 "Give the 'b' command to go to BSD mode.\n");
1350 #if !ENABLE_FEATURE_FDISK_WRITABLE
1351 if (!valid_part_table_flag(MBRbuffer))
1354 if (!valid_part_table_flag(MBRbuffer)) {
1355 if (what == OPEN_MAIN) {
1356 printf("Device contains neither a valid DOS "
1357 "partition table, nor Sun, SGI or OSF "
1360 USE_FEATURE_SUN_LABEL(create_sunlabel();)
1370 #endif /* FEATURE_FDISK_WRITABLE */
1373 USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1376 for (i = 0; i < 4; i++) {
1377 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1378 if (g_partitions != 4)
1379 printf("Ignoring extra extended "
1380 "partition %d\n", i + 1);
1386 for (i = 3; i < g_partitions; i++) {
1387 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 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1401 #if ENABLE_FEATURE_FDISK_WRITABLE
1403 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1404 * If the user hits Enter, DFLT is returned.
1405 * Answers like +10 are interpreted as offsets from BASE.
1407 * There is no default if DFLT is not between LOW and HIGH.
1410 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1414 const char *fmt = "%s (%u-%u, default %u): ";
1416 if (dflt < low || dflt > high) {
1417 fmt = "%s (%u-%u): ";
1422 int use_default = default_ok;
1424 /* ask question and read answer */
1426 printf(fmt, mesg, low, high, dflt);
1427 read_maybe_empty("");
1428 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1429 && *line_ptr != '-' && *line_ptr != '+');
1431 if (*line_ptr == '+' || *line_ptr == '-') {
1432 int minus = (*line_ptr == '-');
1435 i = atoi(line_ptr + 1);
1437 while (isdigit(*++line_ptr))
1440 switch (*line_ptr) {
1443 if (!display_in_cyl_units)
1444 i *= g_heads * g_sectors;
1458 absolute = 1000000000;
1467 bytes = (ullong) i * absolute;
1468 unit = sector_size * units_per_sector;
1469 bytes += unit/2; /* round */
1478 while (isdigit(*line_ptr)) {
1485 printf("Using default value %u\n", i);
1487 if (i >= low && i <= high)
1489 printf("Value is out of range\n");
1495 get_partition(int warn, int max)
1500 i = read_int(1, 0, max, 0, "Partition number") - 1;
1504 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1505 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1506 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1508 printf("Warning: partition %d has empty type\n", i+1);
1515 get_existing_partition(int warn, int max)
1520 for (i = 0; i < max; i++) {
1521 struct pte *pe = &ptes[i];
1522 struct partition *p = pe->part_table;
1524 if (p && !is_cleared_partition(p)) {
1531 printf("Selected partition %d\n", pno+1);
1534 printf("No partition is defined yet!\n");
1538 return get_partition(warn, max);
1542 get_nonexisting_partition(int warn, int max)
1547 for (i = 0; i < max; i++) {
1548 struct pte *pe = &ptes[i];
1549 struct partition *p = pe->part_table;
1551 if (p && is_cleared_partition(p)) {
1558 printf("Selected partition %d\n", pno+1);
1561 printf("All primary partitions have been defined already!\n");
1565 return get_partition(warn, max);
1572 display_in_cyl_units = !display_in_cyl_units;
1574 printf("Changing display/entry units to %s\n",
1579 toggle_active(int i)
1581 struct pte *pe = &ptes[i];
1582 struct partition *p = pe->part_table;
1584 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1585 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1586 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1591 toggle_dos_compatibility_flag(void)
1593 dos_compatible_flag = 1 - dos_compatible_flag;
1594 if (dos_compatible_flag) {
1595 sector_offset = g_sectors;
1596 printf("DOS Compatibility flag is set\n");
1599 printf("DOS Compatibility flag is not set\n");
1604 delete_partition(int i)
1606 struct pte *pe = &ptes[i];
1607 struct partition *p = pe->part_table;
1608 struct partition *q = pe->ext_pointer;
1610 /* Note that for the fifth partition (i == 4) we don't actually
1611 * decrement partitions.
1614 if (warn_geometry())
1615 return; /* C/H/S not set */
1619 sun_delete_partition(i);
1623 sgi_delete_partition(i);
1628 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1630 ptes[ext_index].ext_pointer = NULL;
1631 extended_offset = 0;
1637 if (!q->sys_ind && i > 4) {
1638 /* the last one in the chain - just delete */
1641 clear_partition(ptes[i].ext_pointer);
1642 ptes[i].changed = 1;
1644 /* not the last one - further ones will be moved down */
1646 /* delete this link in the chain */
1647 p = ptes[i-1].ext_pointer;
1649 set_start_sect(p, get_start_sect(q));
1650 set_nr_sects(p, get_nr_sects(q));
1651 ptes[i-1].changed = 1;
1652 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1653 /* the first logical in a longer chain */
1656 if (pe->part_table) /* prevent SEGFAULT */
1657 set_start_sect(pe->part_table,
1658 get_partition_start(pe) -
1660 pe->offset = extended_offset;
1664 if (g_partitions > 5) {
1666 while (i < g_partitions) {
1667 ptes[i] = ptes[i+1];
1671 /* the only logical: clear only */
1672 clear_partition(ptes[i].part_table);
1679 int i, sys, origsys;
1680 struct partition *p;
1682 /* If sgi_label then don't use get_existing_partition,
1683 let the user select a partition, since get_existing_partition()
1684 only works for Linux like partition tables. */
1685 if (!LABEL_IS_SGI) {
1686 i = get_existing_partition(0, g_partitions);
1688 i = get_partition(0, g_partitions);
1692 p = ptes[i].part_table;
1693 origsys = sys = get_sysid(i);
1695 /* if changing types T to 0 is allowed, then
1696 the reverse change must be allowed, too */
1697 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1698 printf("Partition %d does not exist yet!\n", i + 1);
1702 sys = read_hex(get_sys_types());
1704 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1705 printf("Type 0 means free space to many systems\n"
1706 "(but not to Linux). Having partitions of\n"
1707 "type 0 is probably unwise.\n");
1711 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1712 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1713 printf("You cannot change a partition into"
1714 " an extended one or vice versa\n");
1720 #if ENABLE_FEATURE_SUN_LABEL
1721 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1722 printf("Consider leaving partition 3 "
1723 "as Whole disk (5),\n"
1724 "as SunOS/Solaris expects it and "
1725 "even Linux likes it\n\n");
1727 #if ENABLE_FEATURE_SGI_LABEL
1730 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1731 (i == 8 && sys != 0)
1734 printf("Consider leaving partition 9 "
1735 "as volume header (0),\nand "
1736 "partition 11 as entire volume (6)"
1737 "as IRIX expects it\n\n");
1743 sun_change_sysid(i, sys);
1744 } else if (LABEL_IS_SGI) {
1745 sgi_change_sysid(i, sys);
1749 printf("Changed system type of partition %d "
1750 "to %x (%s)\n", i + 1, sys,
1751 partition_type(sys));
1752 ptes[i].changed = 1;
1753 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1759 #endif /* FEATURE_FDISK_WRITABLE */
1762 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1763 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1764 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1765 * Lubkin Oct. 1991). */
1768 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1770 int spc = g_heads * g_sectors;
1774 *h = ls / g_sectors;
1775 *s = ls % g_sectors + 1; /* sectors count from 1 */
1779 check_consistency(const struct partition *p, int partition)
1781 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1782 unsigned pec, peh, pes; /* physical ending c, h, s */
1783 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1784 unsigned lec, leh, les; /* logical ending c, h, s */
1786 if (!g_heads || !g_sectors || (partition >= 4))
1787 return; /* do not check extended partitions */
1789 /* physical beginning c, h, s */
1790 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1792 pbs = p->sector & 0x3f;
1794 /* physical ending c, h, s */
1795 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1797 pes = p->end_sector & 0x3f;
1799 /* compute logical beginning (c, h, s) */
1800 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1802 /* compute logical ending (c, h, s) */
1803 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1805 /* Same physical / logical beginning? */
1806 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1807 printf("Partition %d has different physical/logical "
1808 "beginnings (non-Linux?):\n", partition + 1);
1809 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1810 printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
1813 /* Same physical / logical ending? */
1814 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1815 printf("Partition %d has different physical/logical "
1816 "endings:\n", partition + 1);
1817 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1818 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1821 /* Ending on cylinder boundary? */
1822 if (peh != (g_heads - 1) || pes != g_sectors) {
1823 printf("Partition %i does not end on cylinder boundary\n",
1829 list_disk_geometry(void)
1831 long long bytes = (total_number_of_sectors << 9);
1832 long megabytes = bytes/1000000;
1834 if (megabytes < 10000)
1835 printf("\nDisk %s: %ld MB, %lld bytes\n",
1836 disk_device, megabytes, bytes);
1838 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1839 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1840 printf("%d heads, %d sectors/track, %d cylinders",
1841 g_heads, g_sectors, g_cylinders);
1842 if (units_per_sector == 1)
1843 printf(", total %llu sectors",
1844 total_number_of_sectors / (sector_size/512));
1845 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1847 units_per_sector, sector_size, units_per_sector * sector_size);
1851 * Check whether partition entries are ordered by their starting positions.
1852 * Return 0 if OK. Return i if partition i should have been earlier.
1853 * Two separate checks: primary and logical partitions.
1856 wrong_p_order(int *prev)
1858 const struct pte *pe;
1859 const struct partition *p;
1860 ullong last_p_start_pos = 0, p_start_pos;
1863 for (i = 0; i < g_partitions; i++) {
1866 last_p_start_pos = 0;
1871 p_start_pos = get_partition_start(pe);
1873 if (last_p_start_pos > p_start_pos) {
1879 last_p_start_pos = p_start_pos;
1886 #if ENABLE_FEATURE_FDISK_ADVANCED
1888 * Fix the chain of logicals.
1889 * extended_offset is unchanged, the set of sectors used is unchanged
1890 * The chain is sorted so that sectors increase, and so that
1891 * starting sectors increase.
1893 * After this it may still be that cfdisk doesnt like the table.
1894 * (This is because cfdisk considers expanded parts, from link to
1895 * end of partition, and these may still overlap.)
1897 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1901 fix_chain_of_logicals(void)
1903 int j, oj, ojj, sj, sjj;
1904 struct partition *pj,*pjj,tmp;
1906 /* Stage 1: sort sectors but leave sector of part 4 */
1907 /* (Its sector is the global extended_offset.) */
1909 for (j = 5; j < g_partitions - 1; j++) {
1910 oj = ptes[j].offset;
1911 ojj = ptes[j+1].offset;
1913 ptes[j].offset = ojj;
1914 ptes[j+1].offset = oj;
1915 pj = ptes[j].part_table;
1916 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1917 pjj = ptes[j+1].part_table;
1918 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1919 set_start_sect(ptes[j-1].ext_pointer,
1920 ojj-extended_offset);
1921 set_start_sect(ptes[j].ext_pointer,
1922 oj-extended_offset);
1927 /* Stage 2: sort starting sectors */
1929 for (j = 4; j < g_partitions - 1; j++) {
1930 pj = ptes[j].part_table;
1931 pjj = ptes[j+1].part_table;
1932 sj = get_start_sect(pj);
1933 sjj = get_start_sect(pjj);
1934 oj = ptes[j].offset;
1935 ojj = ptes[j+1].offset;
1936 if (oj+sj > ojj+sjj) {
1940 set_start_sect(pj, ojj+sjj-oj);
1941 set_start_sect(pjj, oj+sj-ojj);
1946 /* Probably something was changed */
1947 for (j = 4; j < g_partitions; j++)
1948 ptes[j].changed = 1;
1953 fix_partition_table_order(void)
1955 struct pte *pei, *pek;
1958 if (!wrong_p_order(NULL)) {
1959 printf("Ordering is already correct\n\n");
1963 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1964 /* partition i should have come earlier, move it */
1965 /* We have to move data in the MBR */
1966 struct partition *pi, *pk, *pe, pbuf;
1970 pe = pei->ext_pointer;
1971 pei->ext_pointer = pek->ext_pointer;
1972 pek->ext_pointer = pe;
1974 pi = pei->part_table;
1975 pk = pek->part_table;
1977 memmove(&pbuf, pi, sizeof(struct partition));
1978 memmove(pi, pk, sizeof(struct partition));
1979 memmove(pk, &pbuf, sizeof(struct partition));
1981 pei->changed = pek->changed = 1;
1985 fix_chain_of_logicals();
1993 list_table(int xtra)
1995 const struct partition *p;
1999 sun_list_table(xtra);
2003 sgi_list_table(xtra);
2007 list_disk_geometry();
2010 xbsd_print_disklabel(xtra);
2014 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2015 but if the device name ends in a digit, say /dev/foo1,
2016 then the partition is called /dev/foo1p3. */
2017 w = strlen(disk_device);
2018 if (w && isdigit(disk_device[w-1]))
2023 // 1 12345678901 12345678901 12345678901 12
2024 printf("%*s Boot Start End Blocks Id System\n",
2027 for (i = 0; i < g_partitions; i++) {
2028 const struct pte *pe = &ptes[i];
2034 if (!p || is_cleared_partition(p))
2037 psects = get_nr_sects(p);
2041 if (sector_size < 1024) {
2042 pblocks /= (1024 / sector_size);
2043 podd = psects % (1024 / sector_size);
2045 if (sector_size > 1024)
2046 pblocks *= (sector_size / 1024);
2048 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2049 partname(disk_device, i+1, w+2),
2050 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2052 (ullong) cround(get_partition_start(pe)), /* start */
2053 (ullong) cround(get_partition_start(pe) + psects /* end */
2054 - (psects ? 1 : 0)),
2055 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2056 p->sys_ind, /* type id */
2057 partition_type(p->sys_ind)); /* type name */
2059 check_consistency(p, i);
2062 /* Is partition table in disk order? It need not be, but... */
2063 /* partition table entries are not checked for correct order if this
2064 is a sgi, sun or aix labeled disk... */
2065 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2067 printf("\nPartition table entries are not in disk order\n");
2071 #if ENABLE_FEATURE_FDISK_ADVANCED
2073 x_list_table(int extend)
2075 const struct pte *pe;
2076 const struct partition *p;
2079 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2080 disk_device, g_heads, g_sectors, g_cylinders);
2081 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2082 for (i = 0; i < g_partitions; i++) {
2084 p = (extend ? pe->ext_pointer : pe->part_table);
2086 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2087 i + 1, p->boot_ind, p->head,
2089 cylinder(p->sector, p->cyl), p->end_head,
2090 sector(p->end_sector),
2091 cylinder(p->end_sector, p->end_cyl),
2092 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2094 check_consistency(p, i);
2100 #if ENABLE_FEATURE_FDISK_WRITABLE
2102 fill_bounds(ullong *first, ullong *last)
2105 const struct pte *pe = &ptes[0];
2106 const struct partition *p;
2108 for (i = 0; i < g_partitions; pe++,i++) {
2110 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2111 first[i] = 0xffffffff;
2114 first[i] = get_partition_start(pe);
2115 last[i] = first[i] + get_nr_sects(p) - 1;
2121 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2123 ullong total, real_s, real_c;
2125 real_s = sector(s) - 1;
2126 real_c = cylinder(s, c);
2127 total = (real_c * g_sectors + real_s) * g_heads + h;
2129 printf("Partition %d contains sector 0\n", n);
2131 printf("Partition %d: head %d greater than maximum %d\n",
2133 if (real_s >= g_sectors)
2134 printf("Partition %d: sector %d greater than "
2135 "maximum %d\n", n, s, g_sectors);
2136 if (real_c >= g_cylinders)
2137 printf("Partition %d: cylinder %llu greater than "
2138 "maximum %d\n", n, real_c + 1, g_cylinders);
2139 if (g_cylinders <= 1024 && start != total)
2140 printf("Partition %d: previous sectors %llu disagrees with "
2141 "total %llu\n", n, start, total);
2149 ullong first[g_partitions], last[g_partitions];
2150 struct partition *p;
2152 if (warn_geometry())
2164 fill_bounds(first, last);
2165 for (i = 0; i < g_partitions; i++) {
2166 struct pte *pe = &ptes[i];
2169 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2170 check_consistency(p, i);
2171 if (get_partition_start(pe) < first[i])
2172 printf("Warning: bad start-of-data in "
2173 "partition %d\n", i + 1);
2174 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2176 total += last[i] + 1 - first[i];
2177 for (j = 0; j < i; j++) {
2178 if ((first[i] >= first[j] && first[i] <= last[j])
2179 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2180 printf("Warning: partition %d overlaps "
2181 "partition %d\n", j + 1, i + 1);
2182 total += first[i] >= first[j] ?
2183 first[i] : first[j];
2184 total -= last[i] <= last[j] ?
2191 if (extended_offset) {
2192 struct pte *pex = &ptes[ext_index];
2193 ullong e_last = get_start_sect(pex->part_table) +
2194 get_nr_sects(pex->part_table) - 1;
2196 for (i = 4; i < g_partitions; i++) {
2198 p = ptes[i].part_table;
2200 if (i != 4 || i + 1 < g_partitions)
2201 printf("Warning: partition %d "
2202 "is empty\n", i + 1);
2203 } else if (first[i] < extended_offset || last[i] > e_last) {
2204 printf("Logical partition %d not entirely in "
2205 "partition %d\n", i + 1, ext_index + 1);
2210 if (total > g_heads * g_sectors * g_cylinders)
2211 printf("Total allocated sectors %d greater than the maximum "
2212 "%d\n", total, g_heads * g_sectors * g_cylinders);
2214 total = g_heads * g_sectors * g_cylinders - total;
2216 printf("%d unallocated sectors\n", total);
2221 add_partition(int n, int sys)
2223 char mesg[256]; /* 48 does not suffice in Japanese */
2224 int i, num_read = 0;
2225 struct partition *p = ptes[n].part_table;
2226 struct partition *q = ptes[ext_index].part_table;
2228 ullong start, stop = 0;
2229 ullong first[g_partitions], last[g_partitions];
2231 if (p && p->sys_ind) {
2232 printf(msg_part_already_defined, n + 1);
2235 fill_bounds(first, last);
2237 start = sector_offset;
2238 if (display_in_cyl_units || !total_number_of_sectors)
2239 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2241 limit = total_number_of_sectors - 1;
2242 if (extended_offset) {
2243 first[ext_index] = extended_offset;
2244 last[ext_index] = get_start_sect(q) +
2245 get_nr_sects(q) - 1;
2248 start = extended_offset + sector_offset;
2249 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2251 if (display_in_cyl_units)
2252 for (i = 0; i < g_partitions; i++)
2253 first[i] = (cround(first[i]) - 1) * units_per_sector;
2255 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2258 for (i = 0; i < g_partitions; i++) {
2261 if (start == ptes[i].offset)
2262 start += sector_offset;
2263 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2264 if (start >= first[i] && start <= lastplusoff)
2265 start = lastplusoff + 1;
2269 if (start >= temp+units_per_sector && num_read) {
2270 printf("Sector %lld is already allocated\n", temp);
2274 if (!num_read && start == temp) {
2277 saved_start = start;
2278 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2280 if (display_in_cyl_units) {
2281 start = (start - 1) * units_per_sector;
2282 if (start < saved_start) start = saved_start;
2286 } while (start != temp || !num_read);
2287 if (n > 4) { /* NOT for fifth partition */
2288 struct pte *pe = &ptes[n];
2290 pe->offset = start - sector_offset;
2291 if (pe->offset == extended_offset) { /* must be corrected */
2293 if (sector_offset == 1)
2298 for (i = 0; i < g_partitions; i++) {
2299 struct pte *pe = &ptes[i];
2301 if (start < pe->offset && limit >= pe->offset)
2302 limit = pe->offset - 1;
2303 if (start < first[i] && limit >= first[i])
2304 limit = first[i] - 1;
2306 if (start > limit) {
2307 printf("No free sectors available\n");
2312 if (cround(start) == cround(limit)) {
2315 snprintf(mesg, sizeof(mesg),
2316 "Last %s or +size or +sizeM or +sizeK",
2317 str_units(SINGULAR));
2318 stop = read_int(cround(start), cround(limit), cround(limit),
2319 cround(start), mesg);
2320 if (display_in_cyl_units) {
2321 stop = stop * units_per_sector - 1;
2327 set_partition(n, 0, start, stop, sys);
2329 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2331 if (IS_EXTENDED(sys)) {
2332 struct pte *pe4 = &ptes[4];
2333 struct pte *pen = &ptes[n];
2336 pen->ext_pointer = p;
2337 pe4->offset = extended_offset = start;
2338 pe4->sectorbuffer = xzalloc(sector_size);
2339 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2340 pe4->ext_pointer = pe4->part_table + 1;
2349 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2350 struct pte *pe = &ptes[g_partitions];
2352 pe->sectorbuffer = xzalloc(sector_size);
2353 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2354 pe->ext_pointer = pe->part_table + 1;
2359 add_partition(g_partitions - 1, LINUX_NATIVE);
2365 int i, free_primary = 0;
2367 if (warn_geometry())
2371 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2375 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2379 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2380 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2381 "table first (use 'o'). This will destroy the present disk contents.\n");
2385 for (i = 0; i < 4; i++)
2386 free_primary += !ptes[i].part_table->sys_ind;
2388 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2389 printf("The maximum number of partitions has been created\n");
2393 if (!free_primary) {
2394 if (extended_offset)
2397 printf("You must delete some partition and add "
2398 "an extended partition first\n");
2401 snprintf(line, sizeof(line),
2404 " p primary partition (1-4)\n",
2406 "l logical (5 or over)" : "e extended"));
2408 c = read_nonempty(line);
2409 if (c == 'p' || c == 'P') {
2410 i = get_nonexisting_partition(0, 4);
2412 add_partition(i, LINUX_NATIVE);
2415 if (c == 'l' && extended_offset) {
2419 if (c == 'e' && !extended_offset) {
2420 i = get_nonexisting_partition(0, 4);
2422 add_partition(i, EXTENDED);
2425 printf("Invalid partition number "
2426 "for type '%c'\n", c);
2437 for (i = 0; i < 3; i++)
2438 if (ptes[i].changed)
2439 ptes[3].changed = 1;
2440 for (i = 3; i < g_partitions; i++) {
2441 struct pte *pe = &ptes[i];
2444 write_part_table_flag(pe->sectorbuffer);
2445 write_sector(pe->offset, pe->sectorbuffer);
2449 else if (LABEL_IS_SGI) {
2450 /* no test on change? the printf below might be mistaken */
2453 else if (LABEL_IS_SUN) {
2456 for (i = 0; i < 8; i++)
2457 if (ptes[i].changed)
2463 printf("The partition table has been altered!\n\n");
2464 reread_partition_table(1);
2468 reread_partition_table(int leave)
2472 printf("Calling ioctl() to re-read partition table\n");
2474 /* sleep(2); Huh? */
2475 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2476 "WARNING: rereading partition table "
2477 "failed, kernel still uses old table");
2481 "\nWARNING: If you have created or modified any DOS 6.x\n"
2482 "partitions, please see the fdisk manual page for additional\n"
2487 if (ENABLE_FEATURE_CLEAN_UP)
2492 #endif /* FEATURE_FDISK_WRITABLE */
2494 #if ENABLE_FEATURE_FDISK_ADVANCED
2495 #define MAX_PER_LINE 16
2497 print_buffer(char *pbuffer)
2501 for (i = 0, l = 0; i < sector_size; i++, l++) {
2503 printf("0x%03X:", i);
2504 printf(" %02X", (unsigned char) pbuffer[i]);
2505 if (l == MAX_PER_LINE - 1) {
2520 printf("Device: %s\n", disk_device);
2521 if (LABEL_IS_SGI || LABEL_IS_SUN)
2522 print_buffer(MBRbuffer);
2524 for (i = 3; i < g_partitions; i++)
2525 print_buffer(ptes[i].sectorbuffer);
2532 struct pte *pe = &ptes[i];
2533 struct partition *p = pe->part_table;
2536 if (warn_geometry())
2538 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2539 printf("Partition %d has no data area\n", i + 1);
2542 first = get_partition_start(pe);
2543 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2544 "New beginning of data") - pe->offset;
2546 if (new != get_nr_sects(p)) {
2547 first = get_nr_sects(p) + get_start_sect(p) - new;
2548 set_nr_sects(p, first);
2549 set_start_sect(p, new);
2561 c = tolower(read_nonempty("Expert command (m for help): "));
2569 move_begin(get_partition(0, g_partitions));
2572 user_cylinders = g_cylinders =
2573 read_int(1, g_cylinders, 1048576, 0,
2574 "Number of cylinders");
2576 sun_set_ncyl(g_cylinders);
2586 else if (LABEL_IS_SUN)
2588 else if (LABEL_IS_DOS)
2593 fix_partition_table_order();
2596 #if ENABLE_FEATURE_SGI_LABEL
2601 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2620 if (ENABLE_FEATURE_CLEAN_UP)
2627 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2628 "Number of sectors");
2629 if (dos_compatible_flag) {
2630 sector_offset = g_sectors;
2631 printf("Warning: setting sector offset for DOS "
2640 write_table(); /* does not return */
2644 sun_set_pcylcount();
2651 #endif /* ADVANCED mode */
2654 is_ide_cdrom_or_tape(const char *device)
2658 struct stat statbuf;
2661 /* No device was given explicitly, and we are trying some
2662 likely things. But opening /dev/hdc may produce errors like
2663 "hdc: tray open or drive not ready"
2664 if it happens to be a CD-ROM drive. It even happens that
2665 the process hangs on the attempt to read a music CD.
2666 So try to be careful. This only works since 2.1.73. */
2668 if (strncmp("/dev/hd", device, 7))
2671 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2672 procf = fopen(buf, "r");
2673 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2674 is_ide = (!strncmp(buf, "cdrom", 5) ||
2675 !strncmp(buf, "tape", 4));
2677 /* Now when this proc file does not exist, skip the
2678 device when it is read-only. */
2679 if (stat(device, &statbuf) == 0)
2680 is_ide = ((statbuf.st_mode & 0222) == 0);
2689 open_list_and_close(const char *device, int user_specified)
2693 disk_device = device;
2694 if (setjmp(listingbuf))
2696 if (!user_specified)
2697 if (is_ide_cdrom_or_tape(device))
2700 /* Open disk_device, save file descriptor to dev_fd */
2702 gb = get_boot(TRY_ONLY);
2703 if (gb > 0) { /* I/O error */
2704 /* Ignore other errors, since we try IDE
2705 and SCSI hard disks which may not be
2706 installed on the system. */
2707 if (user_specified || errno == EACCES)
2708 bb_perror_msg("can't open '%s'", device);
2712 if (gb < 0) { /* no DOS signature */
2713 list_disk_geometry();
2716 #if ENABLE_FEATURE_OSF_LABEL
2717 if (bsd_trydev(device) < 0)
2719 printf("Disk %s doesn't contain a valid "
2720 "partition table\n", device);
2723 #if ENABLE_FEATURE_FDISK_WRITABLE
2724 if (!LABEL_IS_SUN && g_partitions > 4) {
2725 delete_partition(ext_index);
2733 /* for fdisk -l: try all things in /proc/partitions
2734 that look like a partition name (do not end in a digit) */
2736 list_devs_in_proc_partititons(void)
2739 char line[100], ptname[100], devname[120], *s;
2742 procpt = fopen_or_warn("/proc/partitions", "r");
2744 while (fgets(line, sizeof(line), procpt)) {
2745 if (sscanf(line, " %d %d %d %[^\n ]",
2746 &ma, &mi, &sz, ptname) != 4)
2748 for (s = ptname; *s; s++)
2752 sprintf(devname, "/dev/%s", ptname);
2753 open_list_and_close(devname, 0);
2755 #if ENABLE_FEATURE_CLEAN_UP
2760 #if ENABLE_FEATURE_FDISK_WRITABLE
2762 unknown_command(int c)
2764 printf("%c: unknown command\n", c);
2768 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2769 int fdisk_main(int argc, char **argv)
2774 * fdisk -l [-b sectorsize] [-u] device ...
2775 * fdisk -s [partition] ...
2776 * fdisk [-b sectorsize] [-u] device
2778 * Options -C, -H, -S set the geometry.
2782 close_dev_fd(); /* needed: fd 3 must not stay closed */
2784 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2785 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2786 §or_size, &user_cylinders, &user_heads, &user_sectors);
2789 if (opt & OPT_b) { // -b
2790 /* Ugly: this sector size is really per device,
2791 so cannot be combined with multiple disks,
2792 and the same goes for the C/H/S options.
2794 if (sector_size != 512 && sector_size != 1024
2795 && sector_size != 2048)
2798 user_set_sector_size = 1;
2800 if (user_heads <= 0 || user_heads >= 256)
2802 if (user_sectors <= 0 || user_sectors >= 64)
2805 display_in_cyl_units = 0; // -u
2807 #if ENABLE_FEATURE_FDISK_WRITABLE
2814 open_list_and_close(*argv, 1);
2817 /* we don't have device names, */
2818 /* use /proc/partitions instead */
2819 list_devs_in_proc_partititons();
2822 #if ENABLE_FEATURE_FDISK_WRITABLE
2826 #if ENABLE_FEATURE_FDISK_BLKSIZE
2833 for (j = 0; j < argc; j++) {
2834 unsigned long long size;
2835 fd = xopen(argv[j], O_RDONLY);
2836 size = bb_BLKGETSIZE_sectors(fd) / 2;
2839 printf("%lld\n", size);
2841 printf("%s: %lld\n", argv[j], size);
2847 #if ENABLE_FEATURE_FDISK_WRITABLE
2851 disk_device = argv[0];
2852 get_boot(OPEN_MAIN);
2855 /* OSF label, and no DOS label */
2856 printf("Detected an OSF/1 disklabel on %s, entering "
2857 "disklabel mode\n", disk_device);
2859 /*Why do we do this? It seems to be counter-intuitive*/
2860 current_label_type = LABEL_DOS;
2861 /* If we return we may want to make an empty DOS label? */
2867 c = tolower(read_nonempty("Command (m for help): "));
2871 toggle_active(get_partition(1, g_partitions));
2872 else if (LABEL_IS_SUN)
2873 toggle_sunflags(get_partition(1, g_partitions),
2875 else if (LABEL_IS_SGI)
2876 sgi_set_bootpartition(
2877 get_partition(1, g_partitions));
2883 printf("\nThe current boot file is: %s\n",
2884 sgi_get_bootfile());
2885 if (read_maybe_empty("Please enter the name of the "
2886 "new boot file: ") == '\n')
2887 printf("Boot file unchanged\n");
2889 sgi_set_bootfile(line_ptr);
2891 #if ENABLE_FEATURE_OSF_LABEL
2898 toggle_dos_compatibility_flag();
2899 else if (LABEL_IS_SUN)
2900 toggle_sunflags(get_partition(1, g_partitions),
2902 else if (LABEL_IS_SGI)
2903 sgi_set_swappartition(
2904 get_partition(1, g_partitions));
2911 /* If sgi_label then don't use get_existing_partition,
2912 let the user select a partition, since
2913 get_existing_partition() only works for Linux-like
2915 if (!LABEL_IS_SGI) {
2916 j = get_existing_partition(1, g_partitions);
2918 j = get_partition(1, g_partitions);
2921 delete_partition(j);
2930 list_types(get_sys_types());
2945 if (ENABLE_FEATURE_CLEAN_UP)
2950 #if ENABLE_FEATURE_SUN_LABEL
2964 write_table(); /* does not return */
2966 #if ENABLE_FEATURE_FDISK_ADVANCED
2969 printf("\n\tSorry, no experts menu for SGI "
2970 "partition tables available\n\n");
2981 #endif /* FEATURE_FDISK_WRITABLE */