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 */
15 #include <sys/mount.h>
16 #if !defined(BLKSSZGET)
17 # define BLKSSZGET _IO(0x12, 104)
21 /* Looks like someone forgot to add this to config system */
22 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
23 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
24 # define IF_FEATURE_FDISK_BLKSIZE(a)
27 #define DEFAULT_SECTOR_SIZE 512
28 #define DEFAULT_SECTOR_SIZE_STR "512"
29 #define MAX_SECTOR_SIZE 2048
30 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
31 #define MAXIMUM_PARTS 60
33 #define ACTIVE_FLAG 0x80
36 #define WIN98_EXTENDED 0x0f
37 #define LINUX_PARTITION 0x81
38 #define LINUX_SWAP 0x82
39 #define LINUX_NATIVE 0x83
40 #define LINUX_EXTENDED 0x85
41 #define LINUX_LVM 0x8e
42 #define LINUX_RAID 0xfd
52 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
56 /* Used for sector numbers. Today's disk sizes make it necessary */
57 typedef unsigned long long ullong;
61 unsigned char sectors;
62 unsigned short cylinders;
66 #define HDIO_GETGEO 0x0301 /* get device geometry */
68 static const char msg_building_new_label[] ALIGN1 =
69 "Building a new %s. Changes will remain in memory only,\n"
70 "until you decide to write them. After that the previous content\n"
71 "won't be recoverable.\n\n";
73 static const char msg_part_already_defined[] ALIGN1 =
74 "Partition %d is already defined, delete it before re-adding\n";
78 unsigned char boot_ind; /* 0x80 - active */
79 unsigned char head; /* starting head */
80 unsigned char sector; /* starting sector */
81 unsigned char cyl; /* starting cylinder */
82 unsigned char sys_ind; /* what partition type */
83 unsigned char end_head; /* end head */
84 unsigned char end_sector; /* end sector */
85 unsigned char end_cyl; /* end cylinder */
86 unsigned char start4[4]; /* starting sector counting from 0 */
87 unsigned char size4[4]; /* nr of sectors in partition */
90 static const char unable_to_open[] ALIGN1 = "can't open '%s'";
91 static const char unable_to_read[] ALIGN1 = "can't read from %s";
92 static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
95 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
98 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
100 #if ENABLE_FEATURE_SUN_LABEL
101 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
102 #define STATIC_SUN static
104 #define LABEL_IS_SUN 0
105 #define STATIC_SUN extern
108 #if ENABLE_FEATURE_SGI_LABEL
109 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
110 #define STATIC_SGI static
112 #define LABEL_IS_SGI 0
113 #define STATIC_SGI extern
116 #if ENABLE_FEATURE_AIX_LABEL
117 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
118 #define STATIC_AIX static
120 #define LABEL_IS_AIX 0
121 #define STATIC_AIX extern
124 #if ENABLE_FEATURE_OSF_LABEL
125 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
126 #define STATIC_OSF static
128 #define LABEL_IS_OSF 0
129 #define STATIC_OSF extern
132 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
134 static void update_units(void);
135 #if ENABLE_FEATURE_FDISK_WRITABLE
136 static void change_units(void);
137 static void reread_partition_table(int leave);
138 static void delete_partition(int i);
139 static int get_partition(int warn, int max);
140 static void list_types(const char *const *sys);
141 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
143 static const char *partition_type(unsigned char type);
144 static void get_geometry(void);
145 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
146 static int get_boot(enum action what);
148 static int get_boot(void);
154 static unsigned get_start_sect(const struct partition *p);
155 static unsigned get_nr_sects(const struct partition *p);
158 * per partition table entry data
160 * The four primary partitions have the same sectorbuffer (MBRbuffer)
161 * and have NULL ext_pointer.
162 * Each logical partition table entry has two pointers, one for the
163 * partition and one link to the next one.
166 struct partition *part_table; /* points into sectorbuffer */
167 struct partition *ext_pointer; /* points into sectorbuffer */
168 ullong offset; /* disk sector number */
169 char *sectorbuffer; /* disk sector contents */
170 #if ENABLE_FEATURE_FDISK_WRITABLE
171 char changed; /* boolean */
175 /* DOS partition types */
177 static const char *const i386_sys_types[] = {
181 "\x05" "Extended", /* DOS 3.3+ extended partition */
182 "\x06" "FAT16", /* DOS 16-bit >=32M */
183 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
184 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
185 "\x0b" "Win95 FAT32",
186 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
187 "\x0e" "Win95 FAT16 (LBA)",
188 "\x0f" "Win95 Ext'd (LBA)",
189 "\x11" "Hidden FAT12",
190 "\x12" "Compaq diagnostics",
191 "\x14" "Hidden FAT16 <32M",
192 "\x16" "Hidden FAT16",
193 "\x17" "Hidden HPFS/NTFS",
194 "\x1b" "Hidden Win95 FAT32",
195 "\x1c" "Hidden W95 FAT32 (LBA)",
196 "\x1e" "Hidden W95 FAT16 (LBA)",
197 "\x3c" "Part.Magic recovery",
198 "\x41" "PPC PReP Boot",
200 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
201 "\x80" "Old Minix", /* Minix 1.4a and earlier */
202 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
203 "\x82" "Linux swap", /* also Solaris */
205 "\x84" "OS/2 hidden C: drive",
206 "\x85" "Linux extended",
207 "\x86" "NTFS volume set",
208 "\x87" "NTFS volume set",
210 "\x9f" "BSD/OS", /* BSDI */
211 "\xa0" "Thinkpad hibernation",
212 "\xa5" "FreeBSD", /* various BSD flavours */
216 "\xab" "Darwin boot",
219 "\xbe" "Solaris boot",
221 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
222 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
223 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
224 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
225 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
226 autodetect using persistent
228 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
231 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
232 "\x09" "AIX bootable", /* AIX data or Coherent */
234 "\x18" "AST SmartSleep",
237 "\x40" "Venix 80286",
239 "\x4e" "QNX4.x 2nd part",
240 "\x4f" "QNX4.x 3rd part",
242 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
243 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
244 "\x53" "OnTrack DM6 Aux3",
248 "\x5c" "Priam Edisk",
250 "\x64" "Novell Netware 286",
251 "\x65" "Novell Netware 386",
252 "\x70" "DiskSecure Multi-Boot",
255 "\x94" "Amoeba BBT", /* (bad block table) */
257 "\xbb" "Boot Wizard hidden",
258 "\xc1" "DRDOS/sec (FAT-12)",
259 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
260 "\xc6" "DRDOS/sec (FAT-16)",
262 "\xda" "Non-FS data",
263 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
264 Concurrent DOS or CTOS */
265 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
266 "\xdf" "BootIt", /* BootIt EMBRM */
267 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
268 extended partition */
269 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
270 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
271 partition < 1024 cyl. */
273 "\xf4" "SpeedStor", /* SpeedStor large partition */
274 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
275 "\xff" "BBT", /* Xenix Bad Block Table */
281 dev_fd = 3 /* the disk */
288 const char *disk_device;
289 int g_partitions; // = 4; /* maximum partition + 1 */
290 unsigned units_per_sector; // = 1;
291 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
292 unsigned user_set_sector_size;
293 unsigned sector_offset; // = 1;
294 unsigned g_heads, g_sectors, g_cylinders;
295 smallint /* enum label_type */ current_label_type;
296 smallint display_in_cyl_units; // = 1;
297 #if ENABLE_FEATURE_OSF_LABEL
298 smallint possibly_osf_label;
301 smallint listing; /* no aborts for fdisk -l */
302 smallint dos_compatible_flag; // = 1;
303 #if ENABLE_FEATURE_FDISK_WRITABLE
305 smallint nowarn; /* no warnings for fdisk -l/-s */
307 int ext_index; /* the prime extended partition */
308 unsigned user_cylinders, user_heads, user_sectors;
309 unsigned pt_heads, pt_sectors;
310 unsigned kern_heads, kern_sectors;
311 ullong extended_offset; /* offset of link pointers */
312 ullong total_number_of_sectors;
315 char line_buffer[80];
316 char partname_buffer[80];
317 /* Raw disk label. For DOS-type partition tables the MBR,
318 * with descriptions of the primary partitions. */
319 char MBRbuffer[MAX_SECTOR_SIZE];
320 /* Partition tables */
321 struct pte ptes[MAXIMUM_PARTS];
323 #define G (*ptr_to_globals)
324 #define line_ptr (G.line_ptr )
325 #define disk_device (G.disk_device )
326 #define g_partitions (G.g_partitions )
327 #define units_per_sector (G.units_per_sector )
328 #define sector_size (G.sector_size )
329 #define user_set_sector_size (G.user_set_sector_size)
330 #define sector_offset (G.sector_offset )
331 #define g_heads (G.g_heads )
332 #define g_sectors (G.g_sectors )
333 #define g_cylinders (G.g_cylinders )
334 #define current_label_type (G.current_label_type )
335 #define display_in_cyl_units (G.display_in_cyl_units)
336 #define possibly_osf_label (G.possibly_osf_label )
337 #define listing (G.listing )
338 #define dos_compatible_flag (G.dos_compatible_flag )
339 #define nowarn (G.nowarn )
340 #define ext_index (G.ext_index )
341 #define user_cylinders (G.user_cylinders )
342 #define user_heads (G.user_heads )
343 #define user_sectors (G.user_sectors )
344 #define pt_heads (G.pt_heads )
345 #define pt_sectors (G.pt_sectors )
346 #define kern_heads (G.kern_heads )
347 #define kern_sectors (G.kern_sectors )
348 #define extended_offset (G.extended_offset )
349 #define total_number_of_sectors (G.total_number_of_sectors)
350 #define listingbuf (G.listingbuf )
351 #define line_buffer (G.line_buffer )
352 #define partname_buffer (G.partname_buffer)
353 #define MBRbuffer (G.MBRbuffer )
354 #define ptes (G.ptes )
355 #define INIT_G() do { \
356 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
357 sector_size = DEFAULT_SECTOR_SIZE; \
360 display_in_cyl_units = 1; \
361 units_per_sector = 1; \
362 dos_compatible_flag = 1; \
366 /* TODO: move to libbb? */
367 static ullong bb_BLKGETSIZE_sectors(int fd)
370 unsigned long longsectors;
372 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
373 /* Got bytes, convert to 512 byte sectors */
376 /* Needs temp of type long */
377 if (ioctl(fd, BLKGETSIZE, &longsectors))
383 #define IS_EXTENDED(i) \
384 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
386 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
388 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
390 #define pt_offset(b, n) \
391 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
393 #define sector(s) ((s) & 0x3f)
395 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
397 #define hsc2sector(h,s,c) \
398 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
400 #define set_hsc(h,s,c,sector) \
402 s = sector % g_sectors + 1; \
403 sector /= g_sectors; \
404 h = sector % g_heads; \
407 s |= (sector >> 2) & 0xc0; \
413 /* Not really closing, but making sure it is open, and to harmless place */
414 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
417 #if ENABLE_FEATURE_FDISK_WRITABLE
418 /* Read line; return 0 or first printable char */
420 read_line(const char *prompt)
424 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
426 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
428 if (line_buffer[sz-1] == '\n')
429 line_buffer[--sz] = '\0';
431 line_ptr = line_buffer;
432 while (*line_ptr && !isgraph(*line_ptr))
439 * Return partition name - uses static storage
442 partname(const char *dev, int pno, int lth)
449 bufp = partname_buffer;
450 bufsiz = sizeof(partname_buffer);
455 if (isdigit(dev[w-1]))
458 /* devfs kludge - note: fdisk partition names are not supposed
459 to equal kernel names, so there is no reason to do this */
460 if (strcmp(dev + w - 4, "disc") == 0) {
468 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
469 lth-wp-2, w, dev, p, pno);
471 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
476 #if ENABLE_FEATURE_FDISK_WRITABLE
478 set_all_unchanged(void)
482 for (i = 0; i < MAXIMUM_PARTS; i++)
486 static ALWAYS_INLINE void
491 #endif /* FEATURE_FDISK_WRITABLE */
493 static ALWAYS_INLINE struct partition *
494 get_part_table(int i)
496 return ptes[i].part_table;
501 { /* n==1: use singular */
503 return display_in_cyl_units ? "cylinder" : "sector";
504 return display_in_cyl_units ? "cylinders" : "sectors";
508 valid_part_table_flag(const char *mbuffer)
510 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
513 #if ENABLE_FEATURE_FDISK_WRITABLE
514 static ALWAYS_INLINE void
515 write_part_table_flag(char *b)
522 read_nonempty(const char *mesg)
524 while (!read_line(mesg))
530 read_maybe_empty(const char *mesg)
532 if (!read_line(mesg)) {
533 line_ptr = line_buffer;
541 read_hex(const char *const *sys)
545 read_nonempty("Hex code (type L to list codes): ");
546 if (*line_ptr == 'l' || *line_ptr == 'L') {
550 v = bb_strtoul(line_ptr, NULL, 16);
552 /* Bad input also triggers this */
557 #endif /* FEATURE_FDISK_WRITABLE */
559 static void fdisk_fatal(const char *why)
563 longjmp(listingbuf, 1);
565 bb_error_msg_and_die(why, disk_device);
569 seek_sector(ullong secno)
571 secno *= sector_size;
572 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
573 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
574 fdisk_fatal(unable_to_seek);
576 if (secno > MAXINT(off_t)
577 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
579 fdisk_fatal(unable_to_seek);
584 #if ENABLE_FEATURE_FDISK_WRITABLE
586 write_sector(ullong secno, const void *buf)
589 xwrite(dev_fd, buf, sector_size);
594 #include "fdisk_aix.c"
597 unsigned char info[128]; /* Informative text string */
598 unsigned char spare0[14];
600 unsigned char spare1;
602 unsigned char spare2;
605 unsigned char spare1[246]; /* Boot information etc. */
606 unsigned short rspeed; /* Disk rotational speed */
607 unsigned short pcylcount; /* Physical cylinder count */
608 unsigned short sparecyl; /* extra sects per cylinder */
609 unsigned char spare2[4]; /* More magic... */
610 unsigned short ilfact; /* Interleave factor */
611 unsigned short ncyl; /* Data cylinder count */
612 unsigned short nacyl; /* Alt. cylinder count */
613 unsigned short ntrks; /* Tracks per cylinder */
614 unsigned short nsect; /* Sectors per track */
615 unsigned char spare3[4]; /* Even more magic... */
616 struct sun_partinfo {
617 uint32_t start_cylinder;
618 uint32_t num_sectors;
620 unsigned short magic; /* Magic number */
621 unsigned short csum; /* Label xor'd checksum */
623 #define sunlabel ((sun_partition *)MBRbuffer)
624 STATIC_OSF void bsd_select(void);
625 STATIC_OSF void xbsd_print_disklabel(int);
626 #include "fdisk_osf.c"
628 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
630 fdisk_swap16(uint16_t x)
632 return (x << 8) | (x >> 8);
636 fdisk_swap32(uint32_t x)
639 ((x & 0xFF00) << 8) |
640 ((x & 0xFF0000) >> 8) |
645 STATIC_SGI const char *const sgi_sys_types[];
646 STATIC_SGI unsigned sgi_get_num_sectors(int i);
647 STATIC_SGI int sgi_get_sysid(int i);
648 STATIC_SGI void sgi_delete_partition(int i);
649 STATIC_SGI void sgi_change_sysid(int i, int sys);
650 STATIC_SGI void sgi_list_table(int xtra);
651 #if ENABLE_FEATURE_FDISK_ADVANCED
652 STATIC_SGI void sgi_set_xcyl(void);
654 STATIC_SGI int verify_sgi(int verbose);
655 STATIC_SGI void sgi_add_partition(int n, int sys);
656 STATIC_SGI void sgi_set_swappartition(int i);
657 STATIC_SGI const char *sgi_get_bootfile(void);
658 STATIC_SGI void sgi_set_bootfile(const char* aFile);
659 STATIC_SGI void create_sgiinfo(void);
660 STATIC_SGI void sgi_write_table(void);
661 STATIC_SGI void sgi_set_bootpartition(int i);
662 #include "fdisk_sgi.c"
664 STATIC_SUN const char *const sun_sys_types[];
665 STATIC_SUN void sun_delete_partition(int i);
666 STATIC_SUN void sun_change_sysid(int i, int sys);
667 STATIC_SUN void sun_list_table(int xtra);
668 STATIC_SUN void add_sun_partition(int n, int sys);
669 #if ENABLE_FEATURE_FDISK_ADVANCED
670 STATIC_SUN void sun_set_alt_cyl(void);
671 STATIC_SUN void sun_set_ncyl(int cyl);
672 STATIC_SUN void sun_set_xcyl(void);
673 STATIC_SUN void sun_set_ilfact(void);
674 STATIC_SUN void sun_set_rspeed(void);
675 STATIC_SUN void sun_set_pcylcount(void);
677 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
678 STATIC_SUN void verify_sun(void);
679 STATIC_SUN void sun_write_table(void);
680 #include "fdisk_sun.c"
683 #if ENABLE_FEATURE_FDISK_WRITABLE
684 /* start_sect and nr_sects are stored little endian on all machines */
685 /* moreover, they are not aligned correctly */
687 store4_little_endian(unsigned char *cp, unsigned val)
694 #endif /* FEATURE_FDISK_WRITABLE */
697 read4_little_endian(const unsigned char *cp)
699 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
702 #if ENABLE_FEATURE_FDISK_WRITABLE
704 set_start_sect(struct partition *p, unsigned start_sect)
706 store4_little_endian(p->start4, start_sect);
711 get_start_sect(const struct partition *p)
713 return read4_little_endian(p->start4);
716 #if ENABLE_FEATURE_FDISK_WRITABLE
718 set_nr_sects(struct partition *p, unsigned nr_sects)
720 store4_little_endian(p->size4, nr_sects);
725 get_nr_sects(const struct partition *p)
727 return read4_little_endian(p->size4);
730 /* Allocate a buffer and read a partition table sector */
732 read_pte(struct pte *pe, ullong offset)
735 pe->sectorbuffer = xzalloc(sector_size);
737 /* xread would make us abort - bad for fdisk -l */
738 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
739 fdisk_fatal(unable_to_read);
740 #if ENABLE_FEATURE_FDISK_WRITABLE
743 pe->part_table = pe->ext_pointer = NULL;
747 get_partition_start(const struct pte *pe)
749 return pe->offset + get_start_sect(pe->part_table);
752 #if ENABLE_FEATURE_FDISK_WRITABLE
754 * Avoid warning about DOS partitions when no DOS partition was changed.
755 * Here a heuristic "is probably dos partition".
756 * We might also do the opposite and warn in all cases except
757 * for "is probably nondos partition".
761 is_dos_partition(int t)
763 return (t == 1 || t == 4 || t == 6 ||
764 t == 0x0b || t == 0x0c || t == 0x0e ||
765 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
766 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
767 t == 0xc1 || t == 0xc4 || t == 0xc6);
774 puts("Command Action");
776 puts("a\ttoggle a read only flag"); /* sun */
777 puts("b\tedit bsd disklabel");
778 puts("c\ttoggle the mountable flag"); /* sun */
779 puts("d\tdelete a partition");
780 puts("l\tlist known partition types");
781 puts("n\tadd a new partition");
782 puts("o\tcreate a new empty DOS partition table");
783 puts("p\tprint the partition table");
784 puts("q\tquit without saving changes");
785 puts("s\tcreate a new empty Sun disklabel"); /* sun */
786 puts("t\tchange a partition's system id");
787 puts("u\tchange display/entry units");
788 puts("v\tverify the partition table");
789 puts("w\twrite table to disk and exit");
790 #if ENABLE_FEATURE_FDISK_ADVANCED
791 puts("x\textra functionality (experts only)");
793 } else if (LABEL_IS_SGI) {
794 puts("a\tselect bootable partition"); /* sgi flavour */
795 puts("b\tedit bootfile entry"); /* sgi */
796 puts("c\tselect sgi swap partition"); /* sgi flavour */
797 puts("d\tdelete a partition");
798 puts("l\tlist known partition types");
799 puts("n\tadd a new partition");
800 puts("o\tcreate a new empty DOS partition table");
801 puts("p\tprint the partition table");
802 puts("q\tquit without saving changes");
803 puts("s\tcreate a new empty Sun disklabel"); /* sun */
804 puts("t\tchange a partition's system id");
805 puts("u\tchange display/entry units");
806 puts("v\tverify the partition table");
807 puts("w\twrite table to disk and exit");
808 } else if (LABEL_IS_AIX) {
809 puts("o\tcreate a new empty DOS partition table");
810 puts("q\tquit without saving changes");
811 puts("s\tcreate a new empty Sun disklabel"); /* sun */
813 puts("a\ttoggle a bootable flag");
814 puts("b\tedit bsd disklabel");
815 puts("c\ttoggle the dos compatibility flag");
816 puts("d\tdelete a partition");
817 puts("l\tlist known partition types");
818 puts("n\tadd a new partition");
819 puts("o\tcreate a new empty DOS partition table");
820 puts("p\tprint the partition table");
821 puts("q\tquit without saving changes");
822 puts("s\tcreate a new empty Sun disklabel"); /* sun */
823 puts("t\tchange a partition's system id");
824 puts("u\tchange display/entry units");
825 puts("v\tverify the partition table");
826 puts("w\twrite table to disk and exit");
827 #if ENABLE_FEATURE_FDISK_ADVANCED
828 puts("x\textra functionality (experts only)");
832 #endif /* FEATURE_FDISK_WRITABLE */
835 #if ENABLE_FEATURE_FDISK_ADVANCED
839 puts("Command Action");
841 puts("a\tchange number of alternate cylinders"); /*sun*/
842 puts("c\tchange number of cylinders");
843 puts("d\tprint the raw data in the partition table");
844 puts("e\tchange number of extra sectors per cylinder");/*sun*/
845 puts("h\tchange number of heads");
846 puts("i\tchange interleave factor"); /*sun*/
847 puts("o\tchange rotation speed (rpm)"); /*sun*/
848 puts("p\tprint the partition table");
849 puts("q\tquit without saving changes");
850 puts("r\treturn to main menu");
851 puts("s\tchange number of sectors/track");
852 puts("v\tverify the partition table");
853 puts("w\twrite table to disk and exit");
854 puts("y\tchange number of physical cylinders"); /*sun*/
855 } else if (LABEL_IS_SGI) {
856 puts("b\tmove beginning of data in a partition"); /* !sun */
857 puts("c\tchange number of cylinders");
858 puts("d\tprint the raw data in the partition table");
859 puts("e\tlist extended partitions"); /* !sun */
860 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
861 puts("h\tchange number of heads");
862 puts("p\tprint the partition table");
863 puts("q\tquit without saving changes");
864 puts("r\treturn to main menu");
865 puts("s\tchange number of sectors/track");
866 puts("v\tverify the partition table");
867 puts("w\twrite table to disk and exit");
868 } else if (LABEL_IS_AIX) {
869 puts("b\tmove beginning of data in a partition"); /* !sun */
870 puts("c\tchange number of cylinders");
871 puts("d\tprint the raw data in the partition table");
872 puts("e\tlist extended partitions"); /* !sun */
873 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
874 puts("h\tchange number of heads");
875 puts("p\tprint the partition table");
876 puts("q\tquit without saving changes");
877 puts("r\treturn to main menu");
878 puts("s\tchange number of sectors/track");
879 puts("v\tverify the partition table");
880 puts("w\twrite table to disk and exit");
882 puts("b\tmove beginning of data in a partition"); /* !sun */
883 puts("c\tchange number of cylinders");
884 puts("d\tprint the raw data in the partition table");
885 puts("e\tlist extended partitions"); /* !sun */
886 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
887 #if ENABLE_FEATURE_SGI_LABEL
888 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
890 puts("h\tchange number of heads");
891 puts("p\tprint the partition table");
892 puts("q\tquit without saving changes");
893 puts("r\treturn to main menu");
894 puts("s\tchange number of sectors/track");
895 puts("v\tverify the partition table");
896 puts("w\twrite table to disk and exit");
899 #endif /* ADVANCED mode */
901 #if ENABLE_FEATURE_FDISK_WRITABLE
902 static const char *const *
906 LABEL_IS_SUN ? sun_sys_types :
907 LABEL_IS_SGI ? sgi_sys_types :
911 #define get_sys_types() i386_sys_types
912 #endif /* FEATURE_FDISK_WRITABLE */
915 partition_type(unsigned char type)
918 const char *const *types = get_sys_types();
920 for (i = 0; types[i]; i++)
921 if ((unsigned char)types[i][0] == type)
928 #if ENABLE_FEATURE_FDISK_WRITABLE
932 return LABEL_IS_SUN ? sunlabel->infos[i].id :
933 (LABEL_IS_SGI ? sgi_get_sysid(i) :
934 ptes[i].part_table->sys_ind);
938 list_types(const char *const *sys)
943 unsigned done, next, size;
946 for (size = 0; sys[size]; size++)
950 for (i = COLS-1; i >= 0; i--) {
951 done += (size + i - done) / (i + 1);
952 last[COLS-1 - i] = done;
957 printf("%c%2x %-22.22s", i ? ' ' : '\n',
958 (unsigned char)sys[next][0],
960 next = last[i++] + done;
961 if (i >= COLS || next >= last[i]) {
965 } while (done < last[0]);
968 #endif /* FEATURE_FDISK_WRITABLE */
971 is_cleared_partition(const struct partition *p)
973 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
974 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
975 get_start_sect(p) || get_nr_sects(p));
979 clear_partition(struct partition *p)
983 memset(p, 0, sizeof(struct partition));
986 #if ENABLE_FEATURE_FDISK_WRITABLE
988 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
994 p = ptes[i].ext_pointer;
995 offset = extended_offset;
997 p = ptes[i].part_table;
998 offset = ptes[i].offset;
1002 set_start_sect(p, start - offset);
1003 set_nr_sects(p, stop - start + 1);
1004 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1005 start = g_heads * g_sectors * 1024 - 1;
1006 set_hsc(p->head, p->sector, p->cyl, start);
1007 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1008 stop = g_heads * g_sectors * 1024 - 1;
1009 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1010 ptes[i].changed = 1;
1017 if (g_heads && g_sectors && g_cylinders)
1020 printf("Unknown value(s) for:");
1026 printf(" cylinders");
1028 #if ENABLE_FEATURE_FDISK_WRITABLE
1029 " (settable in the extra functions menu)"
1038 int cyl_units = g_heads * g_sectors;
1040 if (display_in_cyl_units && cyl_units)
1041 units_per_sector = cyl_units;
1043 units_per_sector = 1; /* in sectors */
1046 #if ENABLE_FEATURE_FDISK_WRITABLE
1048 warn_cylinders(void)
1050 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1052 "The number of cylinders for this disk is set to %d.\n"
1053 "There is nothing wrong with that, but this is larger than 1024,\n"
1054 "and could in certain setups cause problems with:\n"
1055 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1056 "2) booting and partitioning software from other OSs\n"
1057 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1063 read_extended(int ext)
1067 struct partition *p, *q;
1071 pex->ext_pointer = pex->part_table;
1073 p = pex->part_table;
1074 if (!get_start_sect(p)) {
1075 printf("Bad offset in primary extended partition\n");
1079 while (IS_EXTENDED(p->sys_ind)) {
1080 struct pte *pe = &ptes[g_partitions];
1082 if (g_partitions >= MAXIMUM_PARTS) {
1083 /* This is not a Linux restriction, but
1084 this program uses arrays of size MAXIMUM_PARTS.
1085 Do not try to 'improve' this test. */
1086 struct pte *pre = &ptes[g_partitions - 1];
1087 #if ENABLE_FEATURE_FDISK_WRITABLE
1088 printf("Warning: deleting partitions after %d\n",
1092 clear_partition(pre->ext_pointer);
1096 read_pte(pe, extended_offset + get_start_sect(p));
1098 if (!extended_offset)
1099 extended_offset = get_start_sect(p);
1101 q = p = pt_offset(pe->sectorbuffer, 0);
1102 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1103 if (IS_EXTENDED(p->sys_ind)) {
1104 if (pe->ext_pointer)
1105 printf("Warning: extra link "
1106 "pointer in partition table"
1107 " %d\n", g_partitions + 1);
1109 pe->ext_pointer = p;
1110 } else if (p->sys_ind) {
1112 printf("Warning: ignoring extra "
1113 "data in partition table"
1114 " %d\n", g_partitions + 1);
1120 /* very strange code here... */
1121 if (!pe->part_table) {
1122 if (q != pe->ext_pointer)
1125 pe->part_table = q + 1;
1127 if (!pe->ext_pointer) {
1128 if (q != pe->part_table)
1129 pe->ext_pointer = q;
1131 pe->ext_pointer = q + 1;
1134 p = pe->ext_pointer;
1138 #if ENABLE_FEATURE_FDISK_WRITABLE
1139 /* remove empty links */
1141 for (i = 4; i < g_partitions; i++) {
1142 struct pte *pe = &ptes[i];
1144 if (!get_nr_sects(pe->part_table)
1145 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1147 printf("Omitting empty partition (%d)\n", i+1);
1148 delete_partition(i);
1149 goto remove; /* numbering changed */
1155 #if ENABLE_FEATURE_FDISK_WRITABLE
1157 create_doslabel(void)
1161 printf(msg_building_new_label, "DOS disklabel");
1163 current_label_type = LABEL_DOS;
1165 #if ENABLE_FEATURE_OSF_LABEL
1166 possibly_osf_label = 0;
1170 for (i = 510-64; i < 510; i++)
1172 write_part_table_flag(MBRbuffer);
1173 extended_offset = 0;
1174 set_all_unchanged();
1176 get_boot(CREATE_EMPTY_DOS);
1178 #endif /* FEATURE_FDISK_WRITABLE */
1181 get_sectorsize(void)
1183 if (!user_set_sector_size) {
1185 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1187 if (sector_size != DEFAULT_SECTOR_SIZE)
1188 printf("Note: sector size is %d "
1189 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1195 get_kernel_geometry(void)
1197 struct hd_geometry geometry;
1199 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1200 kern_heads = geometry.heads;
1201 kern_sectors = geometry.sectors;
1202 /* never use geometry.cylinders - it is truncated */
1207 get_partition_table_geometry(void)
1209 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1210 struct partition *p;
1211 int i, h, s, hh, ss;
1215 if (!(valid_part_table_flag((char*)bufp)))
1219 for (i = 0; i < 4; i++) {
1220 p = pt_offset(bufp, i);
1221 if (p->sys_ind != 0) {
1222 h = p->end_head + 1;
1223 s = (p->end_sector & 077);
1228 } else if (hh != h || ss != s)
1233 if (!first && !bad) {
1245 sec_fac = sector_size / 512;
1246 #if ENABLE_FEATURE_SUN_LABEL
1247 guess_device_type();
1249 g_heads = g_cylinders = g_sectors = 0;
1250 kern_heads = kern_sectors = 0;
1251 pt_heads = pt_sectors = 0;
1253 get_kernel_geometry();
1254 get_partition_table_geometry();
1256 g_heads = user_heads ? user_heads :
1257 pt_heads ? pt_heads :
1258 kern_heads ? kern_heads : 255;
1259 g_sectors = user_sectors ? user_sectors :
1260 pt_sectors ? pt_sectors :
1261 kern_sectors ? kern_sectors : 63;
1262 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1265 if (dos_compatible_flag)
1266 sector_offset = g_sectors;
1268 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1270 g_cylinders = user_cylinders;
1274 * Opens disk_device and optionally reads MBR.
1275 * FIXME: document what each 'what' value will do!
1277 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1278 * 0: found or created label
1281 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1282 static int get_boot(enum action what)
1284 static int get_boot(void)
1285 #define get_boot(what) get_boot()
1291 for (i = 0; i < 4; i++) {
1292 struct pte *pe = &ptes[i];
1293 pe->part_table = pt_offset(MBRbuffer, i);
1294 pe->ext_pointer = NULL;
1296 pe->sectorbuffer = MBRbuffer;
1297 #if ENABLE_FEATURE_FDISK_WRITABLE
1298 pe->changed = (what == CREATE_EMPTY_DOS);
1302 #if ENABLE_FEATURE_FDISK_WRITABLE
1303 // ALERT! highly idiotic design!
1304 // We end up here when we call get_boot() recursively
1305 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1306 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1307 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1308 // So skip opening device _again_...
1309 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1312 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1315 fd = open(disk_device, O_RDONLY);
1317 if (what == TRY_ONLY)
1319 fdisk_fatal(unable_to_open);
1321 printf("'%s' is opened for read only\n", disk_device);
1323 xmove_fd(fd, dev_fd);
1324 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1325 if (what == TRY_ONLY) {
1329 fdisk_fatal(unable_to_read);
1332 fd = open(disk_device, O_RDONLY);
1335 if (512 != full_read(fd, MBRbuffer, 512)) {
1339 xmove_fd(fd, dev_fd);
1345 #if ENABLE_FEATURE_SUN_LABEL
1346 if (check_sun_label())
1349 #if ENABLE_FEATURE_SGI_LABEL
1350 if (check_sgi_label())
1353 #if ENABLE_FEATURE_AIX_LABEL
1354 if (check_aix_label())
1357 #if ENABLE_FEATURE_OSF_LABEL
1358 if (check_osf_label()) {
1359 possibly_osf_label = 1;
1360 if (!valid_part_table_flag(MBRbuffer)) {
1361 current_label_type = LABEL_OSF;
1364 printf("This disk has both DOS and BSD magic.\n"
1365 "Give the 'b' command to go to BSD mode.\n");
1369 #if !ENABLE_FEATURE_FDISK_WRITABLE
1370 if (!valid_part_table_flag(MBRbuffer))
1373 if (!valid_part_table_flag(MBRbuffer)) {
1374 if (what == OPEN_MAIN) {
1375 printf("Device contains neither a valid DOS "
1376 "partition table, nor Sun, SGI or OSF "
1379 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1389 #endif /* FEATURE_FDISK_WRITABLE */
1392 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1395 for (i = 0; i < 4; i++) {
1396 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1397 if (g_partitions != 4)
1398 printf("Ignoring extra extended "
1399 "partition %d\n", i + 1);
1405 for (i = 3; i < g_partitions; i++) {
1406 struct pte *pe = &ptes[i];
1407 if (!valid_part_table_flag(pe->sectorbuffer)) {
1408 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1409 "table %d will be corrected by w(rite)\n",
1410 pe->sectorbuffer[510],
1411 pe->sectorbuffer[511],
1413 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1420 #if ENABLE_FEATURE_FDISK_WRITABLE
1422 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1423 * If the user hits Enter, DFLT is returned.
1424 * Answers like +10 are interpreted as offsets from BASE.
1426 * There is no default if DFLT is not between LOW and HIGH.
1429 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1433 const char *fmt = "%s (%u-%u, default %u): ";
1435 if (dflt < low || dflt > high) {
1436 fmt = "%s (%u-%u): ";
1441 int use_default = default_ok;
1443 /* ask question and read answer */
1445 printf(fmt, mesg, low, high, dflt);
1446 read_maybe_empty("");
1447 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1448 && *line_ptr != '-' && *line_ptr != '+');
1450 if (*line_ptr == '+' || *line_ptr == '-') {
1451 int minus = (*line_ptr == '-');
1454 i = atoi(line_ptr + 1);
1456 while (isdigit(*++line_ptr))
1459 switch (*line_ptr) {
1462 if (!display_in_cyl_units)
1463 i *= g_heads * g_sectors;
1477 absolute = 1000000000;
1486 bytes = (ullong) i * absolute;
1487 unit = sector_size * units_per_sector;
1488 bytes += unit/2; /* round */
1497 while (isdigit(*line_ptr)) {
1504 printf("Using default value %u\n", i);
1506 if (i >= low && i <= high)
1508 printf("Value is out of range\n");
1514 get_partition(int warn, int max)
1519 i = read_int(1, 0, max, 0, "Partition number") - 1;
1523 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1524 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1525 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1527 printf("Warning: partition %d has empty type\n", i+1);
1534 get_existing_partition(int warn, int max)
1539 for (i = 0; i < max; i++) {
1540 struct pte *pe = &ptes[i];
1541 struct partition *p = pe->part_table;
1543 if (p && !is_cleared_partition(p)) {
1550 printf("Selected partition %d\n", pno+1);
1553 printf("No partition is defined yet!\n");
1557 return get_partition(warn, max);
1561 get_nonexisting_partition(int warn, int max)
1566 for (i = 0; i < max; i++) {
1567 struct pte *pe = &ptes[i];
1568 struct partition *p = pe->part_table;
1570 if (p && is_cleared_partition(p)) {
1577 printf("Selected partition %d\n", pno+1);
1580 printf("All primary partitions have been defined already!\n");
1584 return get_partition(warn, max);
1591 display_in_cyl_units = !display_in_cyl_units;
1593 printf("Changing display/entry units to %s\n",
1598 toggle_active(int i)
1600 struct pte *pe = &ptes[i];
1601 struct partition *p = pe->part_table;
1603 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1604 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1605 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1610 toggle_dos_compatibility_flag(void)
1612 dos_compatible_flag = 1 - dos_compatible_flag;
1613 if (dos_compatible_flag) {
1614 sector_offset = g_sectors;
1615 printf("DOS Compatibility flag is set\n");
1618 printf("DOS Compatibility flag is not set\n");
1623 delete_partition(int i)
1625 struct pte *pe = &ptes[i];
1626 struct partition *p = pe->part_table;
1627 struct partition *q = pe->ext_pointer;
1629 /* Note that for the fifth partition (i == 4) we don't actually
1630 * decrement partitions.
1633 if (warn_geometry())
1634 return; /* C/H/S not set */
1638 sun_delete_partition(i);
1642 sgi_delete_partition(i);
1647 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1649 ptes[ext_index].ext_pointer = NULL;
1650 extended_offset = 0;
1656 if (!q->sys_ind && i > 4) {
1657 /* the last one in the chain - just delete */
1660 clear_partition(ptes[i].ext_pointer);
1661 ptes[i].changed = 1;
1663 /* not the last one - further ones will be moved down */
1665 /* delete this link in the chain */
1666 p = ptes[i-1].ext_pointer;
1668 set_start_sect(p, get_start_sect(q));
1669 set_nr_sects(p, get_nr_sects(q));
1670 ptes[i-1].changed = 1;
1671 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1672 /* the first logical in a longer chain */
1675 if (pe->part_table) /* prevent SEGFAULT */
1676 set_start_sect(pe->part_table,
1677 get_partition_start(pe) -
1679 pe->offset = extended_offset;
1683 if (g_partitions > 5) {
1685 while (i < g_partitions) {
1686 ptes[i] = ptes[i+1];
1690 /* the only logical: clear only */
1691 clear_partition(ptes[i].part_table);
1698 int i, sys, origsys;
1699 struct partition *p;
1701 /* If sgi_label then don't use get_existing_partition,
1702 let the user select a partition, since get_existing_partition()
1703 only works for Linux like partition tables. */
1704 if (!LABEL_IS_SGI) {
1705 i = get_existing_partition(0, g_partitions);
1707 i = get_partition(0, g_partitions);
1711 p = ptes[i].part_table;
1712 origsys = sys = get_sysid(i);
1714 /* if changing types T to 0 is allowed, then
1715 the reverse change must be allowed, too */
1716 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1717 printf("Partition %d does not exist yet!\n", i + 1);
1721 sys = read_hex(get_sys_types());
1723 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1724 printf("Type 0 means free space to many systems\n"
1725 "(but not to Linux). Having partitions of\n"
1726 "type 0 is probably unwise.\n");
1730 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1731 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1732 printf("You cannot change a partition into"
1733 " an extended one or vice versa\n");
1739 #if ENABLE_FEATURE_SUN_LABEL
1740 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1741 printf("Consider leaving partition 3 "
1742 "as Whole disk (5),\n"
1743 "as SunOS/Solaris expects it and "
1744 "even Linux likes it\n\n");
1746 #if ENABLE_FEATURE_SGI_LABEL
1749 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1750 (i == 8 && sys != 0)
1753 printf("Consider leaving partition 9 "
1754 "as volume header (0),\nand "
1755 "partition 11 as entire volume (6)"
1756 "as IRIX expects it\n\n");
1762 sun_change_sysid(i, sys);
1763 } else if (LABEL_IS_SGI) {
1764 sgi_change_sysid(i, sys);
1768 printf("Changed system type of partition %d "
1769 "to %x (%s)\n", i + 1, sys,
1770 partition_type(sys));
1771 ptes[i].changed = 1;
1772 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1778 #endif /* FEATURE_FDISK_WRITABLE */
1781 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1782 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1783 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1784 * Lubkin Oct. 1991). */
1787 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1789 int spc = g_heads * g_sectors;
1793 *h = ls / g_sectors;
1794 *s = ls % g_sectors + 1; /* sectors count from 1 */
1798 check_consistency(const struct partition *p, int partition)
1800 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1801 unsigned pec, peh, pes; /* physical ending c, h, s */
1802 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1803 unsigned lec, leh, les; /* logical ending c, h, s */
1805 if (!g_heads || !g_sectors || (partition >= 4))
1806 return; /* do not check extended partitions */
1808 /* physical beginning c, h, s */
1809 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1811 pbs = p->sector & 0x3f;
1813 /* physical ending c, h, s */
1814 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1816 pes = p->end_sector & 0x3f;
1818 /* compute logical beginning (c, h, s) */
1819 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1821 /* compute logical ending (c, h, s) */
1822 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1824 /* Same physical / logical beginning? */
1825 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1826 printf("Partition %d has different physical/logical "
1827 "beginnings (non-Linux?):\n", partition + 1);
1828 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1829 printf("logical=(%d, %d, %d)\n", lbc, lbh, lbs);
1832 /* Same physical / logical ending? */
1833 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1834 printf("Partition %d has different physical/logical "
1835 "endings:\n", partition + 1);
1836 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1837 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1840 /* Ending on cylinder boundary? */
1841 if (peh != (g_heads - 1) || pes != g_sectors) {
1842 printf("Partition %i does not end on cylinder boundary\n",
1848 list_disk_geometry(void)
1850 long long bytes = (total_number_of_sectors << 9);
1851 long megabytes = bytes/1000000;
1853 if (megabytes < 10000)
1854 printf("\nDisk %s: %ld MB, %lld bytes\n",
1855 disk_device, megabytes, bytes);
1857 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1858 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1859 printf("%d heads, %d sectors/track, %d cylinders",
1860 g_heads, g_sectors, g_cylinders);
1861 if (units_per_sector == 1)
1862 printf(", total %llu sectors",
1863 total_number_of_sectors / (sector_size/512));
1864 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1866 units_per_sector, sector_size, units_per_sector * sector_size);
1870 * Check whether partition entries are ordered by their starting positions.
1871 * Return 0 if OK. Return i if partition i should have been earlier.
1872 * Two separate checks: primary and logical partitions.
1875 wrong_p_order(int *prev)
1877 const struct pte *pe;
1878 const struct partition *p;
1879 ullong last_p_start_pos = 0, p_start_pos;
1882 for (i = 0; i < g_partitions; i++) {
1885 last_p_start_pos = 0;
1890 p_start_pos = get_partition_start(pe);
1892 if (last_p_start_pos > p_start_pos) {
1898 last_p_start_pos = p_start_pos;
1905 #if ENABLE_FEATURE_FDISK_ADVANCED
1907 * Fix the chain of logicals.
1908 * extended_offset is unchanged, the set of sectors used is unchanged
1909 * The chain is sorted so that sectors increase, and so that
1910 * starting sectors increase.
1912 * After this it may still be that cfdisk doesnt like the table.
1913 * (This is because cfdisk considers expanded parts, from link to
1914 * end of partition, and these may still overlap.)
1916 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1920 fix_chain_of_logicals(void)
1922 int j, oj, ojj, sj, sjj;
1923 struct partition *pj,*pjj,tmp;
1925 /* Stage 1: sort sectors but leave sector of part 4 */
1926 /* (Its sector is the global extended_offset.) */
1928 for (j = 5; j < g_partitions - 1; j++) {
1929 oj = ptes[j].offset;
1930 ojj = ptes[j+1].offset;
1932 ptes[j].offset = ojj;
1933 ptes[j+1].offset = oj;
1934 pj = ptes[j].part_table;
1935 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1936 pjj = ptes[j+1].part_table;
1937 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1938 set_start_sect(ptes[j-1].ext_pointer,
1939 ojj-extended_offset);
1940 set_start_sect(ptes[j].ext_pointer,
1941 oj-extended_offset);
1946 /* Stage 2: sort starting sectors */
1948 for (j = 4; j < g_partitions - 1; j++) {
1949 pj = ptes[j].part_table;
1950 pjj = ptes[j+1].part_table;
1951 sj = get_start_sect(pj);
1952 sjj = get_start_sect(pjj);
1953 oj = ptes[j].offset;
1954 ojj = ptes[j+1].offset;
1955 if (oj+sj > ojj+sjj) {
1959 set_start_sect(pj, ojj+sjj-oj);
1960 set_start_sect(pjj, oj+sj-ojj);
1965 /* Probably something was changed */
1966 for (j = 4; j < g_partitions; j++)
1967 ptes[j].changed = 1;
1972 fix_partition_table_order(void)
1974 struct pte *pei, *pek;
1977 if (!wrong_p_order(NULL)) {
1978 printf("Ordering is already correct\n\n");
1982 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1983 /* partition i should have come earlier, move it */
1984 /* We have to move data in the MBR */
1985 struct partition *pi, *pk, *pe, pbuf;
1989 pe = pei->ext_pointer;
1990 pei->ext_pointer = pek->ext_pointer;
1991 pek->ext_pointer = pe;
1993 pi = pei->part_table;
1994 pk = pek->part_table;
1996 memmove(&pbuf, pi, sizeof(struct partition));
1997 memmove(pi, pk, sizeof(struct partition));
1998 memmove(pk, &pbuf, sizeof(struct partition));
2000 pei->changed = pek->changed = 1;
2004 fix_chain_of_logicals();
2012 list_table(int xtra)
2014 const struct partition *p;
2018 sun_list_table(xtra);
2022 sgi_list_table(xtra);
2026 list_disk_geometry();
2029 xbsd_print_disklabel(xtra);
2033 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2034 but if the device name ends in a digit, say /dev/foo1,
2035 then the partition is called /dev/foo1p3. */
2036 w = strlen(disk_device);
2037 if (w && isdigit(disk_device[w-1]))
2042 // 1 12345678901 12345678901 12345678901 12
2043 printf("%*s Boot Start End Blocks Id System\n",
2046 for (i = 0; i < g_partitions; i++) {
2047 const struct pte *pe = &ptes[i];
2053 if (!p || is_cleared_partition(p))
2056 psects = get_nr_sects(p);
2060 if (sector_size < 1024) {
2061 pblocks /= (1024 / sector_size);
2062 podd = psects % (1024 / sector_size);
2064 if (sector_size > 1024)
2065 pblocks *= (sector_size / 1024);
2067 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2068 partname(disk_device, i+1, w+2),
2069 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2071 (ullong) cround(get_partition_start(pe)), /* start */
2072 (ullong) cround(get_partition_start(pe) + psects /* end */
2073 - (psects ? 1 : 0)),
2074 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2075 p->sys_ind, /* type id */
2076 partition_type(p->sys_ind)); /* type name */
2078 check_consistency(p, i);
2081 /* Is partition table in disk order? It need not be, but... */
2082 /* partition table entries are not checked for correct order if this
2083 is a sgi, sun or aix labeled disk... */
2084 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2086 printf("\nPartition table entries are not in disk order\n");
2090 #if ENABLE_FEATURE_FDISK_ADVANCED
2092 x_list_table(int extend)
2094 const struct pte *pe;
2095 const struct partition *p;
2098 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2099 disk_device, g_heads, g_sectors, g_cylinders);
2100 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2101 for (i = 0; i < g_partitions; i++) {
2103 p = (extend ? pe->ext_pointer : pe->part_table);
2105 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2106 i + 1, p->boot_ind, p->head,
2108 cylinder(p->sector, p->cyl), p->end_head,
2109 sector(p->end_sector),
2110 cylinder(p->end_sector, p->end_cyl),
2111 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2113 check_consistency(p, i);
2119 #if ENABLE_FEATURE_FDISK_WRITABLE
2121 fill_bounds(ullong *first, ullong *last)
2124 const struct pte *pe = &ptes[0];
2125 const struct partition *p;
2127 for (i = 0; i < g_partitions; pe++,i++) {
2129 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2130 first[i] = 0xffffffff;
2133 first[i] = get_partition_start(pe);
2134 last[i] = first[i] + get_nr_sects(p) - 1;
2140 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2142 ullong total, real_s, real_c;
2144 real_s = sector(s) - 1;
2145 real_c = cylinder(s, c);
2146 total = (real_c * g_sectors + real_s) * g_heads + h;
2148 printf("Partition %d contains sector 0\n", n);
2150 printf("Partition %d: head %d greater than maximum %d\n",
2152 if (real_s >= g_sectors)
2153 printf("Partition %d: sector %d greater than "
2154 "maximum %d\n", n, s, g_sectors);
2155 if (real_c >= g_cylinders)
2156 printf("Partition %d: cylinder %llu greater than "
2157 "maximum %d\n", n, real_c + 1, g_cylinders);
2158 if (g_cylinders <= 1024 && start != total)
2159 printf("Partition %d: previous sectors %llu disagrees with "
2160 "total %llu\n", n, start, total);
2168 ullong first[g_partitions], last[g_partitions];
2169 struct partition *p;
2171 if (warn_geometry())
2183 fill_bounds(first, last);
2184 for (i = 0; i < g_partitions; i++) {
2185 struct pte *pe = &ptes[i];
2188 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2189 check_consistency(p, i);
2190 if (get_partition_start(pe) < first[i])
2191 printf("Warning: bad start-of-data in "
2192 "partition %d\n", i + 1);
2193 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2195 total += last[i] + 1 - first[i];
2196 for (j = 0; j < i; j++) {
2197 if ((first[i] >= first[j] && first[i] <= last[j])
2198 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2199 printf("Warning: partition %d overlaps "
2200 "partition %d\n", j + 1, i + 1);
2201 total += first[i] >= first[j] ?
2202 first[i] : first[j];
2203 total -= last[i] <= last[j] ?
2210 if (extended_offset) {
2211 struct pte *pex = &ptes[ext_index];
2212 ullong e_last = get_start_sect(pex->part_table) +
2213 get_nr_sects(pex->part_table) - 1;
2215 for (i = 4; i < g_partitions; i++) {
2217 p = ptes[i].part_table;
2219 if (i != 4 || i + 1 < g_partitions)
2220 printf("Warning: partition %d "
2221 "is empty\n", i + 1);
2222 } else if (first[i] < extended_offset || last[i] > e_last) {
2223 printf("Logical partition %d not entirely in "
2224 "partition %d\n", i + 1, ext_index + 1);
2229 if (total > g_heads * g_sectors * g_cylinders)
2230 printf("Total allocated sectors %d greater than the maximum "
2231 "%d\n", total, g_heads * g_sectors * g_cylinders);
2233 total = g_heads * g_sectors * g_cylinders - total;
2235 printf("%d unallocated sectors\n", total);
2240 add_partition(int n, int sys)
2242 char mesg[256]; /* 48 does not suffice in Japanese */
2243 int i, num_read = 0;
2244 struct partition *p = ptes[n].part_table;
2245 struct partition *q = ptes[ext_index].part_table;
2247 ullong start, stop = 0;
2248 ullong first[g_partitions], last[g_partitions];
2250 if (p && p->sys_ind) {
2251 printf(msg_part_already_defined, n + 1);
2254 fill_bounds(first, last);
2256 start = sector_offset;
2257 if (display_in_cyl_units || !total_number_of_sectors)
2258 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2260 limit = total_number_of_sectors - 1;
2261 if (extended_offset) {
2262 first[ext_index] = extended_offset;
2263 last[ext_index] = get_start_sect(q) +
2264 get_nr_sects(q) - 1;
2267 start = extended_offset + sector_offset;
2268 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2270 if (display_in_cyl_units)
2271 for (i = 0; i < g_partitions; i++)
2272 first[i] = (cround(first[i]) - 1) * units_per_sector;
2274 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2277 for (i = 0; i < g_partitions; i++) {
2280 if (start == ptes[i].offset)
2281 start += sector_offset;
2282 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2283 if (start >= first[i] && start <= lastplusoff)
2284 start = lastplusoff + 1;
2288 if (start >= temp+units_per_sector && num_read) {
2289 printf("Sector %lld is already allocated\n", temp);
2293 if (!num_read && start == temp) {
2296 saved_start = start;
2297 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2299 if (display_in_cyl_units) {
2300 start = (start - 1) * units_per_sector;
2301 if (start < saved_start) start = saved_start;
2305 } while (start != temp || !num_read);
2306 if (n > 4) { /* NOT for fifth partition */
2307 struct pte *pe = &ptes[n];
2309 pe->offset = start - sector_offset;
2310 if (pe->offset == extended_offset) { /* must be corrected */
2312 if (sector_offset == 1)
2317 for (i = 0; i < g_partitions; i++) {
2318 struct pte *pe = &ptes[i];
2320 if (start < pe->offset && limit >= pe->offset)
2321 limit = pe->offset - 1;
2322 if (start < first[i] && limit >= first[i])
2323 limit = first[i] - 1;
2325 if (start > limit) {
2326 printf("No free sectors available\n");
2331 if (cround(start) == cround(limit)) {
2334 snprintf(mesg, sizeof(mesg),
2335 "Last %s or +size or +sizeM or +sizeK",
2336 str_units(SINGULAR));
2337 stop = read_int(cround(start), cround(limit), cround(limit),
2338 cround(start), mesg);
2339 if (display_in_cyl_units) {
2340 stop = stop * units_per_sector - 1;
2346 set_partition(n, 0, start, stop, sys);
2348 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2350 if (IS_EXTENDED(sys)) {
2351 struct pte *pe4 = &ptes[4];
2352 struct pte *pen = &ptes[n];
2355 pen->ext_pointer = p;
2356 pe4->offset = extended_offset = start;
2357 pe4->sectorbuffer = xzalloc(sector_size);
2358 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2359 pe4->ext_pointer = pe4->part_table + 1;
2368 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2369 struct pte *pe = &ptes[g_partitions];
2371 pe->sectorbuffer = xzalloc(sector_size);
2372 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2373 pe->ext_pointer = pe->part_table + 1;
2378 add_partition(g_partitions - 1, LINUX_NATIVE);
2384 int i, free_primary = 0;
2386 if (warn_geometry())
2390 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2394 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2398 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2399 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2400 "table first (use 'o'). This will destroy the present disk contents.\n");
2404 for (i = 0; i < 4; i++)
2405 free_primary += !ptes[i].part_table->sys_ind;
2407 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2408 printf("The maximum number of partitions has been created\n");
2412 if (!free_primary) {
2413 if (extended_offset)
2416 printf("You must delete some partition and add "
2417 "an extended partition first\n");
2420 snprintf(line, sizeof(line),
2423 " p primary partition (1-4)\n",
2425 "l logical (5 or over)" : "e extended"));
2427 c = read_nonempty(line);
2428 if (c == 'p' || c == 'P') {
2429 i = get_nonexisting_partition(0, 4);
2431 add_partition(i, LINUX_NATIVE);
2434 if (c == 'l' && extended_offset) {
2438 if (c == 'e' && !extended_offset) {
2439 i = get_nonexisting_partition(0, 4);
2441 add_partition(i, EXTENDED);
2444 printf("Invalid partition number "
2445 "for type '%c'\n", c);
2456 for (i = 0; i < 3; i++)
2457 if (ptes[i].changed)
2458 ptes[3].changed = 1;
2459 for (i = 3; i < g_partitions; i++) {
2460 struct pte *pe = &ptes[i];
2463 write_part_table_flag(pe->sectorbuffer);
2464 write_sector(pe->offset, pe->sectorbuffer);
2468 else if (LABEL_IS_SGI) {
2469 /* no test on change? the printf below might be mistaken */
2472 else if (LABEL_IS_SUN) {
2475 for (i = 0; i < 8; i++)
2476 if (ptes[i].changed)
2482 printf("The partition table has been altered!\n\n");
2483 reread_partition_table(1);
2487 reread_partition_table(int leave)
2491 printf("Calling ioctl() to re-read partition table\n");
2493 /* sleep(2); Huh? */
2494 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2495 "WARNING: rereading partition table "
2496 "failed, kernel still uses old table");
2500 "\nWARNING: If you have created or modified any DOS 6.x\n"
2501 "partitions, please see the fdisk manual page for additional\n"
2506 if (ENABLE_FEATURE_CLEAN_UP)
2511 #endif /* FEATURE_FDISK_WRITABLE */
2513 #if ENABLE_FEATURE_FDISK_ADVANCED
2514 #define MAX_PER_LINE 16
2516 print_buffer(char *pbuffer)
2520 for (i = 0, l = 0; i < sector_size; i++, l++) {
2522 printf("0x%03X:", i);
2523 printf(" %02X", (unsigned char) pbuffer[i]);
2524 if (l == MAX_PER_LINE - 1) {
2539 printf("Device: %s\n", disk_device);
2540 if (LABEL_IS_SGI || LABEL_IS_SUN)
2541 print_buffer(MBRbuffer);
2543 for (i = 3; i < g_partitions; i++)
2544 print_buffer(ptes[i].sectorbuffer);
2551 struct pte *pe = &ptes[i];
2552 struct partition *p = pe->part_table;
2555 if (warn_geometry())
2557 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2558 printf("Partition %d has no data area\n", i + 1);
2561 first = get_partition_start(pe);
2562 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2563 "New beginning of data") - pe->offset;
2565 if (new != get_nr_sects(p)) {
2566 first = get_nr_sects(p) + get_start_sect(p) - new;
2567 set_nr_sects(p, first);
2568 set_start_sect(p, new);
2580 c = tolower(read_nonempty("Expert command (m for help): "));
2588 move_begin(get_partition(0, g_partitions));
2591 user_cylinders = g_cylinders =
2592 read_int(1, g_cylinders, 1048576, 0,
2593 "Number of cylinders");
2595 sun_set_ncyl(g_cylinders);
2605 else if (LABEL_IS_SUN)
2607 else if (LABEL_IS_DOS)
2612 fix_partition_table_order();
2615 #if ENABLE_FEATURE_SGI_LABEL
2620 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2639 if (ENABLE_FEATURE_CLEAN_UP)
2646 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2647 "Number of sectors");
2648 if (dos_compatible_flag) {
2649 sector_offset = g_sectors;
2650 printf("Warning: setting sector offset for DOS "
2659 write_table(); /* does not return */
2663 sun_set_pcylcount();
2670 #endif /* ADVANCED mode */
2673 is_ide_cdrom_or_tape(const char *device)
2677 struct stat statbuf;
2680 /* No device was given explicitly, and we are trying some
2681 likely things. But opening /dev/hdc may produce errors like
2682 "hdc: tray open or drive not ready"
2683 if it happens to be a CD-ROM drive. It even happens that
2684 the process hangs on the attempt to read a music CD.
2685 So try to be careful. This only works since 2.1.73. */
2687 if (strncmp("/dev/hd", device, 7))
2690 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2691 procf = fopen_for_read(buf);
2692 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2693 is_ide = (!strncmp(buf, "cdrom", 5) ||
2694 !strncmp(buf, "tape", 4));
2696 /* Now when this proc file does not exist, skip the
2697 device when it is read-only. */
2698 if (stat(device, &statbuf) == 0)
2699 is_ide = ((statbuf.st_mode & 0222) == 0);
2708 open_list_and_close(const char *device, int user_specified)
2712 disk_device = device;
2713 if (setjmp(listingbuf))
2715 if (!user_specified)
2716 if (is_ide_cdrom_or_tape(device))
2719 /* Open disk_device, save file descriptor to dev_fd */
2721 gb = get_boot(TRY_ONLY);
2722 if (gb > 0) { /* I/O error */
2723 /* Ignore other errors, since we try IDE
2724 and SCSI hard disks which may not be
2725 installed on the system. */
2726 if (user_specified || errno == EACCES)
2727 bb_perror_msg("can't open '%s'", device);
2731 if (gb < 0) { /* no DOS signature */
2732 list_disk_geometry();
2735 #if ENABLE_FEATURE_OSF_LABEL
2736 if (bsd_trydev(device) < 0)
2738 printf("Disk %s doesn't contain a valid "
2739 "partition table\n", device);
2742 #if ENABLE_FEATURE_FDISK_WRITABLE
2743 if (!LABEL_IS_SUN && g_partitions > 4) {
2744 delete_partition(ext_index);
2752 /* for fdisk -l: try all things in /proc/partitions
2753 that look like a partition name (do not end in a digit) */
2755 list_devs_in_proc_partititons(void)
2758 char line[100], ptname[100], devname[120], *s;
2761 procpt = fopen_or_warn("/proc/partitions", "r");
2763 while (fgets(line, sizeof(line), procpt)) {
2764 if (sscanf(line, " %d %d %d %[^\n ]",
2765 &ma, &mi, &sz, ptname) != 4)
2767 for (s = ptname; *s; s++)
2771 sprintf(devname, "/dev/%s", ptname);
2772 open_list_and_close(devname, 0);
2774 #if ENABLE_FEATURE_CLEAN_UP
2779 #if ENABLE_FEATURE_FDISK_WRITABLE
2781 unknown_command(int c)
2783 printf("%c: unknown command\n", c);
2787 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2788 int fdisk_main(int argc, char **argv)
2793 * fdisk -l [-b sectorsize] [-u] device ...
2794 * fdisk -s [partition] ...
2795 * fdisk [-b sectorsize] [-u] device
2797 * Options -C, -H, -S set the geometry.
2801 close_dev_fd(); /* needed: fd 3 must not stay closed */
2803 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2804 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2805 §or_size, &user_cylinders, &user_heads, &user_sectors);
2808 if (opt & OPT_b) { // -b
2809 /* Ugly: this sector size is really per device,
2810 so cannot be combined with multiple disks,
2811 and the same goes for the C/H/S options.
2813 if (sector_size != 512 && sector_size != 1024
2814 && sector_size != 2048)
2817 user_set_sector_size = 1;
2819 if (user_heads <= 0 || user_heads >= 256)
2821 if (user_sectors <= 0 || user_sectors >= 64)
2824 display_in_cyl_units = 0; // -u
2826 #if ENABLE_FEATURE_FDISK_WRITABLE
2833 open_list_and_close(*argv, 1);
2836 /* we don't have device names, */
2837 /* use /proc/partitions instead */
2838 list_devs_in_proc_partititons();
2841 #if ENABLE_FEATURE_FDISK_WRITABLE
2845 #if ENABLE_FEATURE_FDISK_BLKSIZE
2852 for (j = 0; j < argc; j++) {
2853 unsigned long long size;
2854 fd = xopen(argv[j], O_RDONLY);
2855 size = bb_BLKGETSIZE_sectors(fd) / 2;
2858 printf("%lld\n", size);
2860 printf("%s: %lld\n", argv[j], size);
2866 #if ENABLE_FEATURE_FDISK_WRITABLE
2870 disk_device = argv[0];
2871 get_boot(OPEN_MAIN);
2874 /* OSF label, and no DOS label */
2875 printf("Detected an OSF/1 disklabel on %s, entering "
2876 "disklabel mode\n", disk_device);
2878 /*Why do we do this? It seems to be counter-intuitive*/
2879 current_label_type = LABEL_DOS;
2880 /* If we return we may want to make an empty DOS label? */
2886 c = tolower(read_nonempty("Command (m for help): "));
2890 toggle_active(get_partition(1, g_partitions));
2891 else if (LABEL_IS_SUN)
2892 toggle_sunflags(get_partition(1, g_partitions),
2894 else if (LABEL_IS_SGI)
2895 sgi_set_bootpartition(
2896 get_partition(1, g_partitions));
2902 printf("\nThe current boot file is: %s\n",
2903 sgi_get_bootfile());
2904 if (read_maybe_empty("Please enter the name of the "
2905 "new boot file: ") == '\n')
2906 printf("Boot file unchanged\n");
2908 sgi_set_bootfile(line_ptr);
2910 #if ENABLE_FEATURE_OSF_LABEL
2917 toggle_dos_compatibility_flag();
2918 else if (LABEL_IS_SUN)
2919 toggle_sunflags(get_partition(1, g_partitions),
2921 else if (LABEL_IS_SGI)
2922 sgi_set_swappartition(
2923 get_partition(1, g_partitions));
2930 /* If sgi_label then don't use get_existing_partition,
2931 let the user select a partition, since
2932 get_existing_partition() only works for Linux-like
2934 if (!LABEL_IS_SGI) {
2935 j = get_existing_partition(1, g_partitions);
2937 j = get_partition(1, g_partitions);
2940 delete_partition(j);
2949 list_types(get_sys_types());
2964 if (ENABLE_FEATURE_CLEAN_UP)
2969 #if ENABLE_FEATURE_SUN_LABEL
2983 write_table(); /* does not return */
2985 #if ENABLE_FEATURE_FDISK_ADVANCED
2988 printf("\n\tSorry, no experts menu for SGI "
2989 "partition tables available\n\n");
3000 #endif /* FEATURE_FDISK_WRITABLE */