1 /* vi: set sw=4 ts=4: */
2 /* fdisk.c -- Partition table manipulator for Linux.
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
10 #ifndef _LARGEFILE64_SOURCE
12 #define _LARGEFILE64_SOURCE
14 #include <assert.h> /* assert */
17 /* Looks like someone forgot to add this to config system */
18 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
19 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
20 # define USE_FEATURE_FDISK_BLKSIZE(a)
23 #define DEFAULT_SECTOR_SIZE 512
24 #define DEFAULT_SECTOR_SIZE_STR "512"
25 #define MAX_SECTOR_SIZE 2048
26 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
27 #define MAXIMUM_PARTS 60
29 #define ACTIVE_FLAG 0x80
32 #define WIN98_EXTENDED 0x0f
33 #define LINUX_PARTITION 0x81
34 #define LINUX_SWAP 0x82
35 #define LINUX_NATIVE 0x83
36 #define LINUX_EXTENDED 0x85
37 #define LINUX_LVM 0x8e
38 #define LINUX_RAID 0xfd
48 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
52 /* Used for sector numbers. Today's disk sizes make it necessary */
53 typedef unsigned long long ullong;
57 unsigned char sectors;
58 unsigned short cylinders;
62 #define HDIO_GETGEO 0x0301 /* get device geometry */
64 static const char msg_building_new_label[] ALIGN1 =
65 "Building a new %s. Changes will remain in memory only,\n"
66 "until you decide to write them. After that the previous content\n"
67 "won't be recoverable.\n\n";
69 static const char msg_part_already_defined[] ALIGN1 =
70 "Partition %d is already defined, delete it before re-adding\n";
74 unsigned char boot_ind; /* 0x80 - active */
75 unsigned char head; /* starting head */
76 unsigned char sector; /* starting sector */
77 unsigned char cyl; /* starting cylinder */
78 unsigned char sys_ind; /* What partition type */
79 unsigned char end_head; /* end head */
80 unsigned char end_sector; /* end sector */
81 unsigned char end_cyl; /* end cylinder */
82 unsigned char start4[4]; /* starting sector counting from 0 */
83 unsigned char size4[4]; /* nr of sectors in partition */
86 static const char unable_to_open[] ALIGN1 = "cannot open %s";
87 static const char unable_to_read[] ALIGN1 = "cannot read from %s";
88 static const char unable_to_seek[] ALIGN1 = "cannot seek on %s";
89 static const char unable_to_write[] ALIGN1 = "cannot write to %s";
90 static const char ioctl_error[] ALIGN1 = "BLKGETSIZE ioctl failed on %s";
91 static void fdisk_fatal(const char *why) ATTRIBUTE_NORETURN;
94 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
97 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
99 #if ENABLE_FEATURE_SUN_LABEL
100 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
101 #define STATIC_SUN static
103 #define LABEL_IS_SUN 0
104 #define STATIC_SUN extern
107 #if ENABLE_FEATURE_SGI_LABEL
108 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
109 #define STATIC_SGI static
111 #define LABEL_IS_SGI 0
112 #define STATIC_SGI extern
115 #if ENABLE_FEATURE_AIX_LABEL
116 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
117 #define STATIC_AIX static
119 #define LABEL_IS_AIX 0
120 #define STATIC_AIX extern
123 #if ENABLE_FEATURE_OSF_LABEL
124 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
125 #define STATIC_OSF static
127 #define LABEL_IS_OSF 0
128 #define STATIC_OSF extern
131 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
133 static void update_units(void);
134 #if ENABLE_FEATURE_FDISK_WRITABLE
135 static void change_units(void);
136 static void reread_partition_table(int leave);
137 static void delete_partition(int i);
138 static int get_partition(int warn, int max);
139 static void list_types(const char *const *sys);
140 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
142 static const char *partition_type(unsigned char type);
143 static void get_geometry(void);
144 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
145 static int get_boot(enum action what);
147 static int get_boot(void);
153 static unsigned get_start_sect(const struct partition *p);
154 static unsigned get_nr_sects(const struct partition *p);
157 * per partition table entry data
159 * The four primary partitions have the same sectorbuffer (MBRbuffer)
160 * and have NULL ext_pointer.
161 * Each logical partition table entry has two pointers, one for the
162 * partition and one link to the next one.
165 struct partition *part_table; /* points into sectorbuffer */
166 struct partition *ext_pointer; /* points into sectorbuffer */
167 ullong offset; /* disk sector number */
168 char *sectorbuffer; /* disk sector contents */
169 #if ENABLE_FEATURE_FDISK_WRITABLE
170 char changed; /* boolean */
174 /* DOS partition types */
176 static const char *const i386_sys_types[] = {
180 "\x05" "Extended", /* DOS 3.3+ extended partition */
181 "\x06" "FAT16", /* DOS 16-bit >=32M */
182 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
183 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
184 "\x0b" "Win95 FAT32",
185 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
186 "\x0e" "Win95 FAT16 (LBA)",
187 "\x0f" "Win95 Ext'd (LBA)",
188 "\x11" "Hidden FAT12",
189 "\x12" "Compaq diagnostics",
190 "\x14" "Hidden FAT16 <32M",
191 "\x16" "Hidden FAT16",
192 "\x17" "Hidden HPFS/NTFS",
193 "\x1b" "Hidden Win95 FAT32",
194 "\x1c" "Hidden W95 FAT32 (LBA)",
195 "\x1e" "Hidden W95 FAT16 (LBA)",
196 "\x3c" "Part.Magic recovery",
197 "\x41" "PPC PReP Boot",
199 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
200 "\x80" "Old Minix", /* Minix 1.4a and earlier */
201 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
202 "\x82" "Linux swap", /* also Solaris */
204 "\x84" "OS/2 hidden C: drive",
205 "\x85" "Linux extended",
206 "\x86" "NTFS volume set",
207 "\x87" "NTFS volume set",
209 "\x9f" "BSD/OS", /* BSDI */
210 "\xa0" "Thinkpad hibernation",
211 "\xa5" "FreeBSD", /* various BSD flavours */
215 "\xab" "Darwin boot",
218 "\xbe" "Solaris boot",
220 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
221 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
222 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
223 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
224 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
225 autodetect using persistent
227 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
230 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
231 "\x09" "AIX bootable", /* AIX data or Coherent */
233 "\x18" "AST SmartSleep",
236 "\x40" "Venix 80286",
238 "\x4e" "QNX4.x 2nd part",
239 "\x4f" "QNX4.x 3rd part",
241 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
242 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
243 "\x53" "OnTrack DM6 Aux3",
247 "\x5c" "Priam Edisk",
249 "\x64" "Novell Netware 286",
250 "\x65" "Novell Netware 386",
251 "\x70" "DiskSecure Multi-Boot",
254 "\x94" "Amoeba BBT", /* (bad block table) */
256 "\xbb" "Boot Wizard hidden",
257 "\xc1" "DRDOS/sec (FAT-12)",
258 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
259 "\xc6" "DRDOS/sec (FAT-16)",
261 "\xda" "Non-FS data",
262 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
263 Concurrent DOS or CTOS */
264 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
265 "\xdf" "BootIt", /* BootIt EMBRM */
266 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
267 extended partition */
268 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
269 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
270 partition < 1024 cyl. */
272 "\xf4" "SpeedStor", /* SpeedStor large partition */
273 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
274 "\xff" "BBT", /* Xenix Bad Block Table */
280 dev_fd = 3 /* the disk */
287 const char *disk_device;
288 int g_partitions; // = 4; /* maximum partition + 1 */
289 unsigned units_per_sector; // = 1;
290 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
291 unsigned user_set_sector_size;
292 unsigned sector_offset; // = 1;
293 unsigned g_heads, g_sectors, g_cylinders;
294 smallint /* enum label_type */ current_label_type;
295 smallint display_in_cyl_units; // = 1;
296 #if ENABLE_FEATURE_OSF_LABEL
297 smallint possibly_osf_label;
300 smallint listing; /* no aborts for fdisk -l */
301 smallint dos_compatible_flag; // = 1;
302 #if ENABLE_FEATURE_FDISK_WRITABLE
304 smallint nowarn; /* no warnings for fdisk -l/-s */
306 int ext_index; /* the prime extended partition */
307 unsigned user_cylinders, user_heads, user_sectors;
308 unsigned pt_heads, pt_sectors;
309 unsigned kern_heads, kern_sectors;
310 ullong extended_offset; /* offset of link pointers */
311 ullong total_number_of_sectors;
314 char line_buffer[80];
315 char partname_buffer[80];
316 /* Raw disk label. For DOS-type partition tables the MBR,
317 * with descriptions of the primary partitions. */
318 char MBRbuffer[MAX_SECTOR_SIZE];
319 /* Partition tables */
320 struct pte ptes[MAXIMUM_PARTS];
322 #define G (*ptr_to_globals)
323 #define line_ptr (G.line_ptr)
324 #define disk_device (G.disk_device )
325 #define g_partitions (G.g_partitions )
326 #define units_per_sector (G.units_per_sector )
327 #define sector_size (G.sector_size )
328 #define user_set_sector_size (G.user_set_sector_size)
329 #define sector_offset (G.sector_offset )
330 #define g_heads (G.g_heads )
331 #define g_sectors (G.g_sectors )
332 #define g_cylinders (G.g_cylinders )
333 #define current_label_type (G.current_label_type )
334 #define display_in_cyl_units (G.display_in_cyl_units)
335 #define possibly_osf_label (G.possibly_osf_label )
336 #define listing (G.listing )
337 #define dos_compatible_flag (G.dos_compatible_flag )
338 #define nowarn (G.nowarn )
339 #define ext_index (G.ext_index )
340 #define user_cylinders (G.user_cylinders )
341 #define user_heads (G.user_heads )
342 #define user_sectors (G.user_sectors )
343 #define pt_heads (G.pt_heads )
344 #define pt_sectors (G.pt_sectors )
345 #define kern_heads (G.kern_heads )
346 #define kern_sectors (G.kern_sectors )
347 #define extended_offset (G.extended_offset )
348 #define total_number_of_sectors (G.total_number_of_sectors)
349 #define listingbuf (G.listingbuf)
350 #define line_buffer (G.line_buffer)
351 #define partname_buffer (G.partname_buffer)
352 #define MBRbuffer (G.MBRbuffer)
353 #define ptes (G.ptes)
354 #define INIT_G() do { \
355 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
356 sector_size = DEFAULT_SECTOR_SIZE; \
359 display_in_cyl_units = 1; \
360 units_per_sector = 1; \
361 dos_compatible_flag = 1; \
365 /* TODO: move to libbb? */
366 static ullong bb_BLKGETSIZE_sectors(int fd)
369 unsigned long longsectors;
371 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
372 /* got bytes, convert to 512 byte sectors */
375 /* Needs temp of type long */
376 if (ioctl(fd, BLKGETSIZE, &longsectors))
382 #define IS_EXTENDED(i) \
383 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
385 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
387 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
389 #define pt_offset(b, n) \
390 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
392 #define sector(s) ((s) & 0x3f)
394 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
396 #define hsc2sector(h,s,c) \
397 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
399 #define set_hsc(h,s,c,sector) \
401 s = sector % g_sectors + 1; \
402 sector /= g_sectors; \
403 h = sector % g_heads; \
406 s |= (sector >> 2) & 0xc0; \
412 /* Not really closing, but making sure it is open, and to harmless place */
413 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
416 #if ENABLE_FEATURE_FDISK_WRITABLE
417 /* read line; return 0 or first printable char */
419 read_line(const char *prompt)
423 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
425 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
427 if (line_buffer[sz-1] == '\n')
428 line_buffer[--sz] = '\0';
430 line_ptr = line_buffer;
431 while (*line_ptr && !isgraph(*line_ptr))
438 * return partition name - uses static storage
441 partname(const char *dev, int pno, int lth)
448 bufp = partname_buffer;
449 bufsiz = sizeof(partname_buffer);
454 if (isdigit(dev[w-1]))
457 /* devfs kludge - note: fdisk partition names are not supposed
458 to equal kernel names, so there is no reason to do this */
459 if (strcmp(dev + w - 4, "disc") == 0) {
467 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
468 lth-wp-2, w, dev, p, pno);
470 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
475 #if ENABLE_FEATURE_FDISK_WRITABLE
477 set_all_unchanged(void)
481 for (i = 0; i < MAXIMUM_PARTS; i++)
485 static ALWAYS_INLINE void
490 #endif /* FEATURE_FDISK_WRITABLE */
492 static ALWAYS_INLINE struct partition *
493 get_part_table(int i)
495 return ptes[i].part_table;
500 { /* n==1: use singular */
502 return display_in_cyl_units ? "cylinder" : "sector";
503 return display_in_cyl_units ? "cylinders" : "sectors";
507 valid_part_table_flag(const char *mbuffer)
509 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
512 #if ENABLE_FEATURE_FDISK_WRITABLE
513 static ALWAYS_INLINE void
514 write_part_table_flag(char *b)
521 read_nonempty(const char *mesg)
523 while (!read_line(mesg)) /* repeat */;
528 read_maybe_empty(const char *mesg)
530 if (!read_line(mesg)) {
531 line_ptr = line_buffer;
539 read_hex(const char *const *sys)
543 read_nonempty("Hex code (type L to list codes): ");
544 if (*line_ptr == 'l' || *line_ptr == 'L') {
548 v = bb_strtoul(line_ptr, NULL, 16);
550 /* Bad input also triggers this */
555 #endif /* FEATURE_FDISK_WRITABLE */
557 #include "fdisk_aix.c"
560 unsigned char info[128]; /* Informative text string */
561 unsigned char spare0[14];
563 unsigned char spare1;
565 unsigned char spare2;
568 unsigned char spare1[246]; /* Boot information etc. */
569 unsigned short rspeed; /* Disk rotational speed */
570 unsigned short pcylcount; /* Physical cylinder count */
571 unsigned short sparecyl; /* extra sects per cylinder */
572 unsigned char spare2[4]; /* More magic... */
573 unsigned short ilfact; /* Interleave factor */
574 unsigned short ncyl; /* Data cylinder count */
575 unsigned short nacyl; /* Alt. cylinder count */
576 unsigned short ntrks; /* Tracks per cylinder */
577 unsigned short nsect; /* Sectors per track */
578 unsigned char spare3[4]; /* Even more magic... */
579 struct sun_partinfo {
580 uint32_t start_cylinder;
581 uint32_t num_sectors;
583 unsigned short magic; /* Magic number */
584 unsigned short csum; /* Label xor'd checksum */
586 #define sunlabel ((sun_partition *)MBRbuffer)
587 STATIC_OSF void bsd_select(void);
588 STATIC_OSF void xbsd_print_disklabel(int);
589 #include "fdisk_osf.c"
591 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
593 fdisk_swap16(uint16_t x)
595 return (x << 8) | (x >> 8);
599 fdisk_swap32(uint32_t x)
602 ((x & 0xFF00) << 8) |
603 ((x & 0xFF0000) >> 8) |
608 STATIC_SGI const char *const sgi_sys_types[];
609 STATIC_SGI unsigned sgi_get_num_sectors(int i);
610 STATIC_SGI int sgi_get_sysid(int i);
611 STATIC_SGI void sgi_delete_partition(int i);
612 STATIC_SGI void sgi_change_sysid(int i, int sys);
613 STATIC_SGI void sgi_list_table(int xtra);
614 #if ENABLE_FEATURE_FDISK_ADVANCED
615 STATIC_SGI void sgi_set_xcyl(void);
617 STATIC_SGI int verify_sgi(int verbose);
618 STATIC_SGI void sgi_add_partition(int n, int sys);
619 STATIC_SGI void sgi_set_swappartition(int i);
620 STATIC_SGI const char *sgi_get_bootfile(void);
621 STATIC_SGI void sgi_set_bootfile(const char* aFile);
622 STATIC_SGI void create_sgiinfo(void);
623 STATIC_SGI void sgi_write_table(void);
624 STATIC_SGI void sgi_set_bootpartition(int i);
625 #include "fdisk_sgi.c"
627 STATIC_SUN const char *const sun_sys_types[];
628 STATIC_SUN void sun_delete_partition(int i);
629 STATIC_SUN void sun_change_sysid(int i, int sys);
630 STATIC_SUN void sun_list_table(int xtra);
631 STATIC_SUN void add_sun_partition(int n, int sys);
632 #if ENABLE_FEATURE_FDISK_ADVANCED
633 STATIC_SUN void sun_set_alt_cyl(void);
634 STATIC_SUN void sun_set_ncyl(int cyl);
635 STATIC_SUN void sun_set_xcyl(void);
636 STATIC_SUN void sun_set_ilfact(void);
637 STATIC_SUN void sun_set_rspeed(void);
638 STATIC_SUN void sun_set_pcylcount(void);
640 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
641 STATIC_SUN void verify_sun(void);
642 STATIC_SUN void sun_write_table(void);
643 #include "fdisk_sun.c"
645 #if ENABLE_FEATURE_FDISK_WRITABLE
646 /* start_sect and nr_sects are stored little endian on all machines */
647 /* moreover, they are not aligned correctly */
649 store4_little_endian(unsigned char *cp, unsigned val)
656 #endif /* FEATURE_FDISK_WRITABLE */
659 read4_little_endian(const unsigned char *cp)
661 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
664 #if ENABLE_FEATURE_FDISK_WRITABLE
666 set_start_sect(struct partition *p, unsigned start_sect)
668 store4_little_endian(p->start4, start_sect);
673 get_start_sect(const struct partition *p)
675 return read4_little_endian(p->start4);
678 #if ENABLE_FEATURE_FDISK_WRITABLE
680 set_nr_sects(struct partition *p, unsigned nr_sects)
682 store4_little_endian(p->size4, nr_sects);
687 get_nr_sects(const struct partition *p)
689 return read4_little_endian(p->size4);
692 static void fdisk_fatal(const char *why)
696 longjmp(listingbuf, 1);
698 bb_error_msg_and_die(why, disk_device);
702 seek_sector(ullong secno)
704 secno *= sector_size;
705 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
706 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
707 fdisk_fatal(unable_to_seek);
709 if (secno > MAXINT(off_t)
710 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
712 fdisk_fatal(unable_to_seek);
717 #if ENABLE_FEATURE_FDISK_WRITABLE
719 write_sector(ullong secno, char *buf)
722 xwrite(dev_fd, buf, sector_size);
726 /* Allocate a buffer and read a partition table sector */
728 read_pte(struct pte *pe, ullong offset)
731 pe->sectorbuffer = xzalloc(sector_size);
733 /* xread would make us abort - bad for fdisk -l */
734 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
735 fdisk_fatal(unable_to_read);
736 #if ENABLE_FEATURE_FDISK_WRITABLE
739 pe->part_table = pe->ext_pointer = NULL;
743 get_partition_start(const struct pte *pe)
745 return pe->offset + get_start_sect(pe->part_table);
748 #if ENABLE_FEATURE_FDISK_WRITABLE
750 * Avoid warning about DOS partitions when no DOS partition was changed.
751 * Here a heuristic "is probably dos partition".
752 * We might also do the opposite and warn in all cases except
753 * for "is probably nondos partition".
757 is_dos_partition(int t)
759 return (t == 1 || t == 4 || t == 6 ||
760 t == 0x0b || t == 0x0c || t == 0x0e ||
761 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
762 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
763 t == 0xc1 || t == 0xc4 || t == 0xc6);
770 puts("Command Action");
772 puts("a\ttoggle a read only flag"); /* sun */
773 puts("b\tedit bsd disklabel");
774 puts("c\ttoggle the mountable flag"); /* sun */
775 puts("d\tdelete a partition");
776 puts("l\tlist known partition types");
777 puts("n\tadd a new partition");
778 puts("o\tcreate a new empty DOS partition table");
779 puts("p\tprint the partition table");
780 puts("q\tquit without saving changes");
781 puts("s\tcreate a new empty Sun disklabel"); /* sun */
782 puts("t\tchange a partition's system id");
783 puts("u\tchange display/entry units");
784 puts("v\tverify the partition table");
785 puts("w\twrite table to disk and exit");
786 #if ENABLE_FEATURE_FDISK_ADVANCED
787 puts("x\textra functionality (experts only)");
789 } else if (LABEL_IS_SGI) {
790 puts("a\tselect bootable partition"); /* sgi flavour */
791 puts("b\tedit bootfile entry"); /* sgi */
792 puts("c\tselect sgi swap partition"); /* sgi flavour */
793 puts("d\tdelete a partition");
794 puts("l\tlist known partition types");
795 puts("n\tadd a new partition");
796 puts("o\tcreate a new empty DOS partition table");
797 puts("p\tprint the partition table");
798 puts("q\tquit without saving changes");
799 puts("s\tcreate a new empty Sun disklabel"); /* sun */
800 puts("t\tchange a partition's system id");
801 puts("u\tchange display/entry units");
802 puts("v\tverify the partition table");
803 puts("w\twrite table to disk and exit");
804 } else if (LABEL_IS_AIX) {
805 puts("o\tcreate a new empty DOS partition table");
806 puts("q\tquit without saving changes");
807 puts("s\tcreate a new empty Sun disklabel"); /* sun */
809 puts("a\ttoggle a bootable flag");
810 puts("b\tedit bsd disklabel");
811 puts("c\ttoggle the dos compatibility flag");
812 puts("d\tdelete a partition");
813 puts("l\tlist known partition types");
814 puts("n\tadd a new partition");
815 puts("o\tcreate a new empty DOS partition table");
816 puts("p\tprint the partition table");
817 puts("q\tquit without saving changes");
818 puts("s\tcreate a new empty Sun disklabel"); /* sun */
819 puts("t\tchange a partition's system id");
820 puts("u\tchange display/entry units");
821 puts("v\tverify the partition table");
822 puts("w\twrite table to disk and exit");
823 #if ENABLE_FEATURE_FDISK_ADVANCED
824 puts("x\textra functionality (experts only)");
828 #endif /* FEATURE_FDISK_WRITABLE */
831 #if ENABLE_FEATURE_FDISK_ADVANCED
835 puts("Command Action");
837 puts("a\tchange number of alternate cylinders"); /*sun*/
838 puts("c\tchange number of cylinders");
839 puts("d\tprint the raw data in the partition table");
840 puts("e\tchange number of extra sectors per cylinder");/*sun*/
841 puts("h\tchange number of heads");
842 puts("i\tchange interleave factor"); /*sun*/
843 puts("o\tchange rotation speed (rpm)"); /*sun*/
844 puts("p\tprint the partition table");
845 puts("q\tquit without saving changes");
846 puts("r\treturn to main menu");
847 puts("s\tchange number of sectors/track");
848 puts("v\tverify the partition table");
849 puts("w\twrite table to disk and exit");
850 puts("y\tchange number of physical cylinders"); /*sun*/
851 } else if (LABEL_IS_SGI) {
852 puts("b\tmove beginning of data in a partition"); /* !sun */
853 puts("c\tchange number of cylinders");
854 puts("d\tprint the raw data in the partition table");
855 puts("e\tlist extended partitions"); /* !sun */
856 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
857 puts("h\tchange number of heads");
858 puts("p\tprint the partition table");
859 puts("q\tquit without saving changes");
860 puts("r\treturn to main menu");
861 puts("s\tchange number of sectors/track");
862 puts("v\tverify the partition table");
863 puts("w\twrite table to disk and exit");
864 } else if (LABEL_IS_AIX) {
865 puts("b\tmove beginning of data in a partition"); /* !sun */
866 puts("c\tchange number of cylinders");
867 puts("d\tprint the raw data in the partition table");
868 puts("e\tlist extended partitions"); /* !sun */
869 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
870 puts("h\tchange number of heads");
871 puts("p\tprint the partition table");
872 puts("q\tquit without saving changes");
873 puts("r\treturn to main menu");
874 puts("s\tchange number of sectors/track");
875 puts("v\tverify the partition table");
876 puts("w\twrite table to disk and exit");
878 puts("b\tmove beginning of data in a partition"); /* !sun */
879 puts("c\tchange number of cylinders");
880 puts("d\tprint the raw data in the partition table");
881 puts("e\tlist extended partitions"); /* !sun */
882 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
883 #if ENABLE_FEATURE_SGI_LABEL
884 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
886 puts("h\tchange number of heads");
887 puts("p\tprint the partition table");
888 puts("q\tquit without saving changes");
889 puts("r\treturn to main menu");
890 puts("s\tchange number of sectors/track");
891 puts("v\tverify the partition table");
892 puts("w\twrite table to disk and exit");
895 #endif /* ADVANCED mode */
897 #if ENABLE_FEATURE_FDISK_WRITABLE
898 static const char *const *
902 LABEL_IS_SUN ? sun_sys_types :
903 LABEL_IS_SGI ? sgi_sys_types :
907 #define get_sys_types() i386_sys_types
908 #endif /* FEATURE_FDISK_WRITABLE */
911 partition_type(unsigned char type)
914 const char *const *types = get_sys_types();
916 for (i = 0; types[i]; i++)
917 if ((unsigned char)types[i][0] == type)
924 #if ENABLE_FEATURE_FDISK_WRITABLE
928 return LABEL_IS_SUN ? sunlabel->infos[i].id :
929 (LABEL_IS_SGI ? sgi_get_sysid(i) :
930 ptes[i].part_table->sys_ind);
934 list_types(const char *const *sys)
939 unsigned done, next, size;
942 for (size = 0; sys[size]; size++) /* */;
945 for (i = COLS-1; i >= 0; i--) {
946 done += (size + i - done) / (i + 1);
947 last[COLS-1 - i] = done;
952 printf("%c%2x %-22.22s", i ? ' ' : '\n',
953 (unsigned char)sys[next][0],
955 next = last[i++] + done;
956 if (i >= COLS || next >= last[i]) {
960 } while (done < last[0]);
963 #endif /* FEATURE_FDISK_WRITABLE */
966 is_cleared_partition(const struct partition *p)
968 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
969 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
970 get_start_sect(p) || get_nr_sects(p));
974 clear_partition(struct partition *p)
978 memset(p, 0, sizeof(struct partition));
981 #if ENABLE_FEATURE_FDISK_WRITABLE
983 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
989 p = ptes[i].ext_pointer;
990 offset = extended_offset;
992 p = ptes[i].part_table;
993 offset = ptes[i].offset;
997 set_start_sect(p, start - offset);
998 set_nr_sects(p, stop - start + 1);
999 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1000 start = g_heads * g_sectors * 1024 - 1;
1001 set_hsc(p->head, p->sector, p->cyl, start);
1002 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1003 stop = g_heads * g_sectors * 1024 - 1;
1004 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1005 ptes[i].changed = 1;
1012 if (g_heads && g_sectors && g_cylinders)
1015 printf("Unknown value(s) for:");
1021 printf(" cylinders");
1023 #if ENABLE_FEATURE_FDISK_WRITABLE
1024 " (settable in the extra functions menu)"
1033 int cyl_units = g_heads * g_sectors;
1035 if (display_in_cyl_units && cyl_units)
1036 units_per_sector = cyl_units;
1038 units_per_sector = 1; /* in sectors */
1041 #if ENABLE_FEATURE_FDISK_WRITABLE
1043 warn_cylinders(void)
1045 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1047 "The number of cylinders for this disk is set to %d.\n"
1048 "There is nothing wrong with that, but this is larger than 1024,\n"
1049 "and could in certain setups cause problems with:\n"
1050 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1051 "2) booting and partitioning software from other OSs\n"
1052 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1058 read_extended(int ext)
1062 struct partition *p, *q;
1066 pex->ext_pointer = pex->part_table;
1068 p = pex->part_table;
1069 if (!get_start_sect(p)) {
1070 printf("Bad offset in primary extended partition\n");
1074 while (IS_EXTENDED(p->sys_ind)) {
1075 struct pte *pe = &ptes[g_partitions];
1077 if (g_partitions >= MAXIMUM_PARTS) {
1078 /* This is not a Linux restriction, but
1079 this program uses arrays of size MAXIMUM_PARTS.
1080 Do not try to 'improve' this test. */
1081 struct pte *pre = &ptes[g_partitions - 1];
1082 #if ENABLE_FEATURE_FDISK_WRITABLE
1083 printf("Warning: deleting partitions after %d\n",
1087 clear_partition(pre->ext_pointer);
1091 read_pte(pe, extended_offset + get_start_sect(p));
1093 if (!extended_offset)
1094 extended_offset = get_start_sect(p);
1096 q = p = pt_offset(pe->sectorbuffer, 0);
1097 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1098 if (IS_EXTENDED(p->sys_ind)) {
1099 if (pe->ext_pointer)
1100 printf("Warning: extra link "
1101 "pointer in partition table"
1102 " %d\n", g_partitions + 1);
1104 pe->ext_pointer = p;
1105 } else if (p->sys_ind) {
1107 printf("Warning: ignoring extra "
1108 "data in partition table"
1109 " %d\n", g_partitions + 1);
1115 /* very strange code here... */
1116 if (!pe->part_table) {
1117 if (q != pe->ext_pointer)
1120 pe->part_table = q + 1;
1122 if (!pe->ext_pointer) {
1123 if (q != pe->part_table)
1124 pe->ext_pointer = q;
1126 pe->ext_pointer = q + 1;
1129 p = pe->ext_pointer;
1133 #if ENABLE_FEATURE_FDISK_WRITABLE
1134 /* remove empty links */
1136 for (i = 4; i < g_partitions; i++) {
1137 struct pte *pe = &ptes[i];
1139 if (!get_nr_sects(pe->part_table)
1140 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1142 printf("Omitting empty partition (%d)\n", i+1);
1143 delete_partition(i);
1144 goto remove; /* numbering changed */
1150 #if ENABLE_FEATURE_FDISK_WRITABLE
1152 create_doslabel(void)
1156 printf(msg_building_new_label, "DOS disklabel");
1158 current_label_type = LABEL_DOS;
1160 #if ENABLE_FEATURE_OSF_LABEL
1161 possibly_osf_label = 0;
1165 for (i = 510-64; i < 510; i++)
1167 write_part_table_flag(MBRbuffer);
1168 extended_offset = 0;
1169 set_all_unchanged();
1171 get_boot(CREATE_EMPTY_DOS);
1173 #endif /* FEATURE_FDISK_WRITABLE */
1176 get_sectorsize(void)
1178 if (!user_set_sector_size) {
1180 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1182 if (sector_size != DEFAULT_SECTOR_SIZE)
1183 printf("Note: sector size is %d "
1184 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1190 get_kernel_geometry(void)
1192 struct hd_geometry geometry;
1194 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1195 kern_heads = geometry.heads;
1196 kern_sectors = geometry.sectors;
1197 /* never use geometry.cylinders - it is truncated */
1202 get_partition_table_geometry(void)
1204 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1205 struct partition *p;
1206 int i, h, s, hh, ss;
1210 if (!(valid_part_table_flag((char*)bufp)))
1214 for (i = 0; i < 4; i++) {
1215 p = pt_offset(bufp, i);
1216 if (p->sys_ind != 0) {
1217 h = p->end_head + 1;
1218 s = (p->end_sector & 077);
1223 } else if (hh != h || ss != s)
1228 if (!first && !bad) {
1240 sec_fac = sector_size / 512;
1241 #if ENABLE_FEATURE_SUN_LABEL
1242 guess_device_type();
1244 g_heads = g_cylinders = g_sectors = 0;
1245 kern_heads = kern_sectors = 0;
1246 pt_heads = pt_sectors = 0;
1248 get_kernel_geometry();
1249 get_partition_table_geometry();
1251 g_heads = user_heads ? user_heads :
1252 pt_heads ? pt_heads :
1253 kern_heads ? kern_heads : 255;
1254 g_sectors = user_sectors ? user_sectors :
1255 pt_sectors ? pt_sectors :
1256 kern_sectors ? kern_sectors : 63;
1257 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1260 if (dos_compatible_flag)
1261 sector_offset = g_sectors;
1263 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1265 g_cylinders = user_cylinders;
1269 * Opens disk_device and optionally reads MBR.
1270 * FIXME: document what each 'what' value will do!
1272 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1273 * 0: found or created label
1276 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1277 static int get_boot(enum action what)
1279 static int get_boot(void)
1280 #define get_boot(what) get_boot()
1286 for (i = 0; i < 4; i++) {
1287 struct pte *pe = &ptes[i];
1288 pe->part_table = pt_offset(MBRbuffer, i);
1289 pe->ext_pointer = NULL;
1291 pe->sectorbuffer = MBRbuffer;
1292 #if ENABLE_FEATURE_FDISK_WRITABLE
1293 pe->changed = (what == CREATE_EMPTY_DOS);
1297 #if ENABLE_FEATURE_FDISK_WRITABLE
1298 // ALERT! highly idiotic design!
1299 // We end up here when we call get_boot() recursively
1300 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1301 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1302 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1303 // So skip opening device _again_...
1304 if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1307 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1310 fd = open(disk_device, O_RDONLY);
1312 if (what == TRY_ONLY)
1314 fdisk_fatal(unable_to_open);
1316 printf("'%s' is opened for read only\n", disk_device);
1318 xmove_fd(fd, dev_fd);
1319 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1320 if (what == TRY_ONLY) {
1324 fdisk_fatal(unable_to_read);
1327 fd = open(disk_device, O_RDONLY);
1330 if (512 != full_read(fd, MBRbuffer, 512)) {
1334 xmove_fd(fd, dev_fd);
1340 #if ENABLE_FEATURE_SUN_LABEL
1341 if (check_sun_label())
1344 #if ENABLE_FEATURE_SGI_LABEL
1345 if (check_sgi_label())
1348 #if ENABLE_FEATURE_AIX_LABEL
1349 if (check_aix_label())
1352 #if ENABLE_FEATURE_OSF_LABEL
1353 if (check_osf_label()) {
1354 possibly_osf_label = 1;
1355 if (!valid_part_table_flag(MBRbuffer)) {
1356 current_label_type = LABEL_OSF;
1359 printf("This disk has both DOS and BSD magic.\n"
1360 "Give the 'b' command to go to BSD mode.\n");
1364 #if !ENABLE_FEATURE_FDISK_WRITABLE
1365 if (!valid_part_table_flag(MBRbuffer))
1368 if (!valid_part_table_flag(MBRbuffer)) {
1369 if (what == OPEN_MAIN) {
1370 printf("Device contains neither a valid DOS "
1371 "partition table, nor Sun, SGI or OSF "
1374 USE_FEATURE_SUN_LABEL(create_sunlabel();)
1384 #endif /* FEATURE_FDISK_WRITABLE */
1387 USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1390 for (i = 0; i < 4; i++) {
1391 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1392 if (g_partitions != 4)
1393 printf("Ignoring extra extended "
1394 "partition %d\n", i + 1);
1400 for (i = 3; i < g_partitions; i++) {
1401 struct pte *pe = &ptes[i];
1402 if (!valid_part_table_flag(pe->sectorbuffer)) {
1403 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1404 "table %d will be corrected by w(rite)\n",
1405 pe->sectorbuffer[510],
1406 pe->sectorbuffer[511],
1408 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1415 #if ENABLE_FEATURE_FDISK_WRITABLE
1417 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1418 * If the user hits Enter, DFLT is returned.
1419 * Answers like +10 are interpreted as offsets from BASE.
1421 * There is no default if DFLT is not between LOW and HIGH.
1424 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1428 const char *fmt = "%s (%u-%u, default %u): ";
1430 if (dflt < low || dflt > high) {
1431 fmt = "%s (%u-%u): ";
1436 int use_default = default_ok;
1438 /* ask question and read answer */
1440 printf(fmt, mesg, low, high, dflt);
1441 read_maybe_empty("");
1442 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1443 && *line_ptr != '-' && *line_ptr != '+');
1445 if (*line_ptr == '+' || *line_ptr == '-') {
1446 int minus = (*line_ptr == '-');
1449 i = atoi(line_ptr + 1);
1451 while (isdigit(*++line_ptr))
1454 switch (*line_ptr) {
1457 if (!display_in_cyl_units)
1458 i *= g_heads * g_sectors;
1472 absolute = 1000000000;
1481 bytes = (ullong) i * absolute;
1482 unit = sector_size * units_per_sector;
1483 bytes += unit/2; /* round */
1492 while (isdigit(*line_ptr)) {
1499 printf("Using default value %u\n", i);
1501 if (i >= low && i <= high)
1503 printf("Value is out of range\n");
1509 get_partition(int warn, int max)
1514 i = read_int(1, 0, max, 0, "Partition number") - 1;
1518 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1519 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1520 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1522 printf("Warning: partition %d has empty type\n", i+1);
1529 get_existing_partition(int warn, int max)
1534 for (i = 0; i < max; i++) {
1535 struct pte *pe = &ptes[i];
1536 struct partition *p = pe->part_table;
1538 if (p && !is_cleared_partition(p)) {
1545 printf("Selected partition %d\n", pno+1);
1548 printf("No partition is defined yet!\n");
1552 return get_partition(warn, max);
1556 get_nonexisting_partition(int warn, int max)
1561 for (i = 0; i < max; i++) {
1562 struct pte *pe = &ptes[i];
1563 struct partition *p = pe->part_table;
1565 if (p && is_cleared_partition(p)) {
1572 printf("Selected partition %d\n", pno+1);
1575 printf("All primary partitions have been defined already!\n");
1579 return get_partition(warn, max);
1586 display_in_cyl_units = !display_in_cyl_units;
1588 printf("Changing display/entry units to %s\n",
1593 toggle_active(int i)
1595 struct pte *pe = &ptes[i];
1596 struct partition *p = pe->part_table;
1598 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1599 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1600 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1605 toggle_dos_compatibility_flag(void)
1607 dos_compatible_flag = 1 - dos_compatible_flag;
1608 if (dos_compatible_flag) {
1609 sector_offset = g_sectors;
1610 printf("DOS Compatibility flag is set\n");
1613 printf("DOS Compatibility flag is not set\n");
1618 delete_partition(int i)
1620 struct pte *pe = &ptes[i];
1621 struct partition *p = pe->part_table;
1622 struct partition *q = pe->ext_pointer;
1624 /* Note that for the fifth partition (i == 4) we don't actually
1625 * decrement partitions.
1628 if (warn_geometry())
1629 return; /* C/H/S not set */
1633 sun_delete_partition(i);
1637 sgi_delete_partition(i);
1642 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1644 ptes[ext_index].ext_pointer = NULL;
1645 extended_offset = 0;
1651 if (!q->sys_ind && i > 4) {
1652 /* the last one in the chain - just delete */
1655 clear_partition(ptes[i].ext_pointer);
1656 ptes[i].changed = 1;
1658 /* not the last one - further ones will be moved down */
1660 /* delete this link in the chain */
1661 p = ptes[i-1].ext_pointer;
1663 set_start_sect(p, get_start_sect(q));
1664 set_nr_sects(p, get_nr_sects(q));
1665 ptes[i-1].changed = 1;
1666 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1667 /* the first logical in a longer chain */
1670 if (pe->part_table) /* prevent SEGFAULT */
1671 set_start_sect(pe->part_table,
1672 get_partition_start(pe) -
1674 pe->offset = extended_offset;
1678 if (g_partitions > 5) {
1680 while (i < g_partitions) {
1681 ptes[i] = ptes[i+1];
1685 /* the only logical: clear only */
1686 clear_partition(ptes[i].part_table);
1693 int i, sys, origsys;
1694 struct partition *p;
1696 /* If sgi_label then don't use get_existing_partition,
1697 let the user select a partition, since get_existing_partition()
1698 only works for Linux like partition tables. */
1699 if (!LABEL_IS_SGI) {
1700 i = get_existing_partition(0, g_partitions);
1702 i = get_partition(0, g_partitions);
1706 p = ptes[i].part_table;
1707 origsys = sys = get_sysid(i);
1709 /* if changing types T to 0 is allowed, then
1710 the reverse change must be allowed, too */
1711 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1712 printf("Partition %d does not exist yet!\n", i + 1);
1716 sys = read_hex(get_sys_types());
1718 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1719 printf("Type 0 means free space to many systems\n"
1720 "(but not to Linux). Having partitions of\n"
1721 "type 0 is probably unwise.\n");
1725 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1726 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1727 printf("You cannot change a partition into"
1728 " an extended one or vice versa\n");
1734 #if ENABLE_FEATURE_SUN_LABEL
1735 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1736 printf("Consider leaving partition 3 "
1737 "as Whole disk (5),\n"
1738 "as SunOS/Solaris expects it and "
1739 "even Linux likes it\n\n");
1741 #if ENABLE_FEATURE_SGI_LABEL
1744 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1745 (i == 8 && sys != 0)
1748 printf("Consider leaving partition 9 "
1749 "as volume header (0),\nand "
1750 "partition 11 as entire volume (6)"
1751 "as IRIX expects it\n\n");
1757 sun_change_sysid(i, sys);
1758 } else if (LABEL_IS_SGI) {
1759 sgi_change_sysid(i, sys);
1763 printf("Changed system type of partition %d "
1764 "to %x (%s)\n", i + 1, sys,
1765 partition_type(sys));
1766 ptes[i].changed = 1;
1767 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1773 #endif /* FEATURE_FDISK_WRITABLE */
1776 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1777 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1778 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1779 * Lubkin Oct. 1991). */
1782 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1784 int spc = g_heads * g_sectors;
1788 *h = ls / g_sectors;
1789 *s = ls % g_sectors + 1; /* sectors count from 1 */
1793 check_consistency(const struct partition *p, int partition)
1795 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1796 unsigned pec, peh, pes; /* physical ending c, h, s */
1797 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1798 unsigned lec, leh, les; /* logical ending c, h, s */
1800 if (!g_heads || !g_sectors || (partition >= 4))
1801 return; /* do not check extended partitions */
1803 /* physical beginning c, h, s */
1804 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1806 pbs = p->sector & 0x3f;
1808 /* physical ending c, h, s */
1809 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1811 pes = p->end_sector & 0x3f;
1813 /* compute logical beginning (c, h, s) */
1814 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1816 /* compute logical ending (c, h, s) */
1817 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1819 /* Same physical / logical beginning? */
1820 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1821 printf("Partition %d has different physical/logical "
1822 "beginnings (non-Linux?):\n", partition + 1);
1823 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1824 printf("logical=(%d, %d, %d)\n", lbc, lbh, lbs);
1827 /* Same physical / logical ending? */
1828 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1829 printf("Partition %d has different physical/logical "
1830 "endings:\n", partition + 1);
1831 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1832 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1835 /* Ending on cylinder boundary? */
1836 if (peh != (g_heads - 1) || pes != g_sectors) {
1837 printf("Partition %i does not end on cylinder boundary\n",
1843 list_disk_geometry(void)
1845 long long bytes = (total_number_of_sectors << 9);
1846 long megabytes = bytes/1000000;
1848 if (megabytes < 10000)
1849 printf("\nDisk %s: %ld MB, %lld bytes\n",
1850 disk_device, megabytes, bytes);
1852 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1853 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1854 printf("%d heads, %d sectors/track, %d cylinders",
1855 g_heads, g_sectors, g_cylinders);
1856 if (units_per_sector == 1)
1857 printf(", total %llu sectors",
1858 total_number_of_sectors / (sector_size/512));
1859 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1861 units_per_sector, sector_size, units_per_sector * sector_size);
1865 * Check whether partition entries are ordered by their starting positions.
1866 * Return 0 if OK. Return i if partition i should have been earlier.
1867 * Two separate checks: primary and logical partitions.
1870 wrong_p_order(int *prev)
1872 const struct pte *pe;
1873 const struct partition *p;
1874 ullong last_p_start_pos = 0, p_start_pos;
1877 for (i = 0; i < g_partitions; i++) {
1880 last_p_start_pos = 0;
1885 p_start_pos = get_partition_start(pe);
1887 if (last_p_start_pos > p_start_pos) {
1893 last_p_start_pos = p_start_pos;
1900 #if ENABLE_FEATURE_FDISK_ADVANCED
1902 * Fix the chain of logicals.
1903 * extended_offset is unchanged, the set of sectors used is unchanged
1904 * The chain is sorted so that sectors increase, and so that
1905 * starting sectors increase.
1907 * After this it may still be that cfdisk doesnt like the table.
1908 * (This is because cfdisk considers expanded parts, from link to
1909 * end of partition, and these may still overlap.)
1911 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1915 fix_chain_of_logicals(void)
1917 int j, oj, ojj, sj, sjj;
1918 struct partition *pj,*pjj,tmp;
1920 /* Stage 1: sort sectors but leave sector of part 4 */
1921 /* (Its sector is the global extended_offset.) */
1923 for (j = 5; j < g_partitions - 1; j++) {
1924 oj = ptes[j].offset;
1925 ojj = ptes[j+1].offset;
1927 ptes[j].offset = ojj;
1928 ptes[j+1].offset = oj;
1929 pj = ptes[j].part_table;
1930 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1931 pjj = ptes[j+1].part_table;
1932 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1933 set_start_sect(ptes[j-1].ext_pointer,
1934 ojj-extended_offset);
1935 set_start_sect(ptes[j].ext_pointer,
1936 oj-extended_offset);
1941 /* Stage 2: sort starting sectors */
1943 for (j = 4; j < g_partitions - 1; j++) {
1944 pj = ptes[j].part_table;
1945 pjj = ptes[j+1].part_table;
1946 sj = get_start_sect(pj);
1947 sjj = get_start_sect(pjj);
1948 oj = ptes[j].offset;
1949 ojj = ptes[j+1].offset;
1950 if (oj+sj > ojj+sjj) {
1954 set_start_sect(pj, ojj+sjj-oj);
1955 set_start_sect(pjj, oj+sj-ojj);
1960 /* Probably something was changed */
1961 for (j = 4; j < g_partitions; j++)
1962 ptes[j].changed = 1;
1967 fix_partition_table_order(void)
1969 struct pte *pei, *pek;
1972 if (!wrong_p_order(NULL)) {
1973 printf("Ordering is already correct\n\n");
1977 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1978 /* partition i should have come earlier, move it */
1979 /* We have to move data in the MBR */
1980 struct partition *pi, *pk, *pe, pbuf;
1984 pe = pei->ext_pointer;
1985 pei->ext_pointer = pek->ext_pointer;
1986 pek->ext_pointer = pe;
1988 pi = pei->part_table;
1989 pk = pek->part_table;
1991 memmove(&pbuf, pi, sizeof(struct partition));
1992 memmove(pi, pk, sizeof(struct partition));
1993 memmove(pk, &pbuf, sizeof(struct partition));
1995 pei->changed = pek->changed = 1;
1999 fix_chain_of_logicals();
2007 list_table(int xtra)
2009 const struct partition *p;
2013 sun_list_table(xtra);
2017 sgi_list_table(xtra);
2021 list_disk_geometry();
2024 xbsd_print_disklabel(xtra);
2028 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2029 but if the device name ends in a digit, say /dev/foo1,
2030 then the partition is called /dev/foo1p3. */
2031 w = strlen(disk_device);
2032 if (w && isdigit(disk_device[w-1]))
2037 // 1 12345678901 12345678901 12345678901 12
2038 printf("%*s Boot Start End Blocks Id System\n",
2041 for (i = 0; i < g_partitions; i++) {
2042 const struct pte *pe = &ptes[i];
2048 if (!p || is_cleared_partition(p))
2051 psects = get_nr_sects(p);
2055 if (sector_size < 1024) {
2056 pblocks /= (1024 / sector_size);
2057 podd = psects % (1024 / sector_size);
2059 if (sector_size > 1024)
2060 pblocks *= (sector_size / 1024);
2062 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2063 partname(disk_device, i+1, w+2),
2064 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2066 (ullong) cround(get_partition_start(pe)), /* start */
2067 (ullong) cround(get_partition_start(pe) + psects /* end */
2068 - (psects ? 1 : 0)),
2069 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2070 p->sys_ind, /* type id */
2071 partition_type(p->sys_ind)); /* type name */
2073 check_consistency(p, i);
2076 /* Is partition table in disk order? It need not be, but... */
2077 /* partition table entries are not checked for correct order if this
2078 is a sgi, sun or aix labeled disk... */
2079 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2081 printf("\nPartition table entries are not in disk order\n");
2085 #if ENABLE_FEATURE_FDISK_ADVANCED
2087 x_list_table(int extend)
2089 const struct pte *pe;
2090 const struct partition *p;
2093 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2094 disk_device, g_heads, g_sectors, g_cylinders);
2095 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2096 for (i = 0; i < g_partitions; i++) {
2098 p = (extend ? pe->ext_pointer : pe->part_table);
2100 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2101 i + 1, p->boot_ind, p->head,
2103 cylinder(p->sector, p->cyl), p->end_head,
2104 sector(p->end_sector),
2105 cylinder(p->end_sector, p->end_cyl),
2106 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2108 check_consistency(p, i);
2114 #if ENABLE_FEATURE_FDISK_WRITABLE
2116 fill_bounds(ullong *first, ullong *last)
2119 const struct pte *pe = &ptes[0];
2120 const struct partition *p;
2122 for (i = 0; i < g_partitions; pe++,i++) {
2124 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2125 first[i] = 0xffffffff;
2128 first[i] = get_partition_start(pe);
2129 last[i] = first[i] + get_nr_sects(p) - 1;
2135 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2137 ullong total, real_s, real_c;
2139 real_s = sector(s) - 1;
2140 real_c = cylinder(s, c);
2141 total = (real_c * g_sectors + real_s) * g_heads + h;
2143 printf("Partition %d contains sector 0\n", n);
2145 printf("Partition %d: head %d greater than maximum %d\n",
2147 if (real_s >= g_sectors)
2148 printf("Partition %d: sector %d greater than "
2149 "maximum %d\n", n, s, g_sectors);
2150 if (real_c >= g_cylinders)
2151 printf("Partition %d: cylinder %llu greater than "
2152 "maximum %d\n", n, real_c + 1, g_cylinders);
2153 if (g_cylinders <= 1024 && start != total)
2154 printf("Partition %d: previous sectors %llu disagrees with "
2155 "total %llu\n", n, start, total);
2163 ullong first[g_partitions], last[g_partitions];
2164 struct partition *p;
2166 if (warn_geometry())
2178 fill_bounds(first, last);
2179 for (i = 0; i < g_partitions; i++) {
2180 struct pte *pe = &ptes[i];
2183 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2184 check_consistency(p, i);
2185 if (get_partition_start(pe) < first[i])
2186 printf("Warning: bad start-of-data in "
2187 "partition %d\n", i + 1);
2188 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2190 total += last[i] + 1 - first[i];
2191 for (j = 0; j < i; j++) {
2192 if ((first[i] >= first[j] && first[i] <= last[j])
2193 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2194 printf("Warning: partition %d overlaps "
2195 "partition %d\n", j + 1, i + 1);
2196 total += first[i] >= first[j] ?
2197 first[i] : first[j];
2198 total -= last[i] <= last[j] ?
2205 if (extended_offset) {
2206 struct pte *pex = &ptes[ext_index];
2207 ullong e_last = get_start_sect(pex->part_table) +
2208 get_nr_sects(pex->part_table) - 1;
2210 for (i = 4; i < g_partitions; i++) {
2212 p = ptes[i].part_table;
2214 if (i != 4 || i + 1 < g_partitions)
2215 printf("Warning: partition %d "
2216 "is empty\n", i + 1);
2217 } else if (first[i] < extended_offset || last[i] > e_last) {
2218 printf("Logical partition %d not entirely in "
2219 "partition %d\n", i + 1, ext_index + 1);
2224 if (total > g_heads * g_sectors * g_cylinders)
2225 printf("Total allocated sectors %d greater than the maximum "
2226 "%d\n", total, g_heads * g_sectors * g_cylinders);
2228 total = g_heads * g_sectors * g_cylinders - total;
2230 printf("%d unallocated sectors\n", total);
2235 add_partition(int n, int sys)
2237 char mesg[256]; /* 48 does not suffice in Japanese */
2238 int i, num_read = 0;
2239 struct partition *p = ptes[n].part_table;
2240 struct partition *q = ptes[ext_index].part_table;
2242 ullong start, stop = 0;
2243 ullong first[g_partitions], last[g_partitions];
2245 if (p && p->sys_ind) {
2246 printf(msg_part_already_defined, n + 1);
2249 fill_bounds(first, last);
2251 start = sector_offset;
2252 if (display_in_cyl_units || !total_number_of_sectors)
2253 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2255 limit = total_number_of_sectors - 1;
2256 if (extended_offset) {
2257 first[ext_index] = extended_offset;
2258 last[ext_index] = get_start_sect(q) +
2259 get_nr_sects(q) - 1;
2262 start = extended_offset + sector_offset;
2263 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2265 if (display_in_cyl_units)
2266 for (i = 0; i < g_partitions; i++)
2267 first[i] = (cround(first[i]) - 1) * units_per_sector;
2269 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2272 for (i = 0; i < g_partitions; i++) {
2275 if (start == ptes[i].offset)
2276 start += sector_offset;
2277 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2278 if (start >= first[i] && start <= lastplusoff)
2279 start = lastplusoff + 1;
2283 if (start >= temp+units_per_sector && num_read) {
2284 printf("Sector %lld is already allocated\n", temp);
2288 if (!num_read && start == temp) {
2291 saved_start = start;
2292 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2294 if (display_in_cyl_units) {
2295 start = (start - 1) * units_per_sector;
2296 if (start < saved_start) start = saved_start;
2300 } while (start != temp || !num_read);
2301 if (n > 4) { /* NOT for fifth partition */
2302 struct pte *pe = &ptes[n];
2304 pe->offset = start - sector_offset;
2305 if (pe->offset == extended_offset) { /* must be corrected */
2307 if (sector_offset == 1)
2312 for (i = 0; i < g_partitions; i++) {
2313 struct pte *pe = &ptes[i];
2315 if (start < pe->offset && limit >= pe->offset)
2316 limit = pe->offset - 1;
2317 if (start < first[i] && limit >= first[i])
2318 limit = first[i] - 1;
2320 if (start > limit) {
2321 printf("No free sectors available\n");
2326 if (cround(start) == cround(limit)) {
2329 snprintf(mesg, sizeof(mesg),
2330 "Last %s or +size or +sizeM or +sizeK",
2331 str_units(SINGULAR));
2332 stop = read_int(cround(start), cround(limit), cround(limit),
2333 cround(start), mesg);
2334 if (display_in_cyl_units) {
2335 stop = stop * units_per_sector - 1;
2341 set_partition(n, 0, start, stop, sys);
2343 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2345 if (IS_EXTENDED(sys)) {
2346 struct pte *pe4 = &ptes[4];
2347 struct pte *pen = &ptes[n];
2350 pen->ext_pointer = p;
2351 pe4->offset = extended_offset = start;
2352 pe4->sectorbuffer = xzalloc(sector_size);
2353 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2354 pe4->ext_pointer = pe4->part_table + 1;
2363 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2364 struct pte *pe = &ptes[g_partitions];
2366 pe->sectorbuffer = xzalloc(sector_size);
2367 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2368 pe->ext_pointer = pe->part_table + 1;
2373 add_partition(g_partitions - 1, LINUX_NATIVE);
2379 int i, free_primary = 0;
2381 if (warn_geometry())
2385 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2389 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2393 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2394 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2395 "table first (use 'o'). This will destroy the present disk contents.\n");
2399 for (i = 0; i < 4; i++)
2400 free_primary += !ptes[i].part_table->sys_ind;
2402 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2403 printf("The maximum number of partitions has been created\n");
2407 if (!free_primary) {
2408 if (extended_offset)
2411 printf("You must delete some partition and add "
2412 "an extended partition first\n");
2415 snprintf(line, sizeof(line),
2418 " p primary partition (1-4)\n",
2420 "l logical (5 or over)" : "e extended"));
2422 c = read_nonempty(line);
2423 if (c == 'p' || c == 'P') {
2424 i = get_nonexisting_partition(0, 4);
2426 add_partition(i, LINUX_NATIVE);
2429 if (c == 'l' && extended_offset) {
2433 if (c == 'e' && !extended_offset) {
2434 i = get_nonexisting_partition(0, 4);
2436 add_partition(i, EXTENDED);
2439 printf("Invalid partition number "
2440 "for type '%c'\n", c);
2451 for (i = 0; i < 3; i++)
2452 if (ptes[i].changed)
2453 ptes[3].changed = 1;
2454 for (i = 3; i < g_partitions; i++) {
2455 struct pte *pe = &ptes[i];
2458 write_part_table_flag(pe->sectorbuffer);
2459 write_sector(pe->offset, pe->sectorbuffer);
2463 else if (LABEL_IS_SGI) {
2464 /* no test on change? the printf below might be mistaken */
2467 else if (LABEL_IS_SUN) {
2470 for (i = 0; i < 8; i++)
2471 if (ptes[i].changed)
2477 printf("The partition table has been altered!\n\n");
2478 reread_partition_table(1);
2482 reread_partition_table(int leave)
2486 printf("Calling ioctl() to re-read partition table\n");
2488 /* sleep(2); Huh? */
2489 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2490 "WARNING: rereading partition table "
2491 "failed, kernel still uses old table");
2495 "\nWARNING: If you have created or modified any DOS 6.x\n"
2496 "partitions, please see the fdisk manual page for additional\n"
2501 if (ENABLE_FEATURE_CLEAN_UP)
2506 #endif /* FEATURE_FDISK_WRITABLE */
2508 #if ENABLE_FEATURE_FDISK_ADVANCED
2509 #define MAX_PER_LINE 16
2511 print_buffer(char *pbuffer)
2515 for (i = 0, l = 0; i < sector_size; i++, l++) {
2517 printf("0x%03X:", i);
2518 printf(" %02X", (unsigned char) pbuffer[i]);
2519 if (l == MAX_PER_LINE - 1) {
2534 printf("Device: %s\n", disk_device);
2535 if (LABEL_IS_SGI || LABEL_IS_SUN)
2536 print_buffer(MBRbuffer);
2538 for (i = 3; i < g_partitions; i++)
2539 print_buffer(ptes[i].sectorbuffer);
2546 struct pte *pe = &ptes[i];
2547 struct partition *p = pe->part_table;
2550 if (warn_geometry())
2552 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2553 printf("Partition %d has no data area\n", i + 1);
2556 first = get_partition_start(pe);
2557 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2558 "New beginning of data") - pe->offset;
2560 if (new != get_nr_sects(p)) {
2561 first = get_nr_sects(p) + get_start_sect(p) - new;
2562 set_nr_sects(p, first);
2563 set_start_sect(p, new);
2575 c = tolower(read_nonempty("Expert command (m for help): "));
2583 move_begin(get_partition(0, g_partitions));
2586 user_cylinders = g_cylinders =
2587 read_int(1, g_cylinders, 1048576, 0,
2588 "Number of cylinders");
2590 sun_set_ncyl(g_cylinders);
2600 else if (LABEL_IS_SUN)
2602 else if (LABEL_IS_DOS)
2607 fix_partition_table_order();
2610 #if ENABLE_FEATURE_SGI_LABEL
2615 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2634 if (ENABLE_FEATURE_CLEAN_UP)
2641 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2642 "Number of sectors");
2643 if (dos_compatible_flag) {
2644 sector_offset = g_sectors;
2645 printf("Warning: setting sector offset for DOS "
2654 write_table(); /* does not return */
2658 sun_set_pcylcount();
2665 #endif /* ADVANCED mode */
2668 is_ide_cdrom_or_tape(const char *device)
2672 struct stat statbuf;
2675 /* No device was given explicitly, and we are trying some
2676 likely things. But opening /dev/hdc may produce errors like
2677 "hdc: tray open or drive not ready"
2678 if it happens to be a CD-ROM drive. It even happens that
2679 the process hangs on the attempt to read a music CD.
2680 So try to be careful. This only works since 2.1.73. */
2682 if (strncmp("/dev/hd", device, 7))
2685 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2686 procf = fopen(buf, "r");
2687 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2688 is_ide = (!strncmp(buf, "cdrom", 5) ||
2689 !strncmp(buf, "tape", 4));
2691 /* Now when this proc file does not exist, skip the
2692 device when it is read-only. */
2693 if (stat(device, &statbuf) == 0)
2694 is_ide = ((statbuf.st_mode & 0222) == 0);
2703 open_list_and_close(const char *device, int user_specified)
2707 disk_device = device;
2708 if (setjmp(listingbuf))
2710 if (!user_specified)
2711 if (is_ide_cdrom_or_tape(device))
2714 /* Open disk_device, save file descriptor to dev_fd */
2716 gb = get_boot(TRY_ONLY);
2717 if (gb > 0) { /* I/O error */
2718 /* Ignore other errors, since we try IDE
2719 and SCSI hard disks which may not be
2720 installed on the system. */
2721 if (user_specified || errno == EACCES)
2722 bb_perror_msg("can't open '%s'", device);
2726 if (gb < 0) { /* no DOS signature */
2727 list_disk_geometry();
2730 #if ENABLE_FEATURE_OSF_LABEL
2731 if (bsd_trydev(device) < 0)
2733 printf("Disk %s doesn't contain a valid "
2734 "partition table\n", device);
2737 #if ENABLE_FEATURE_FDISK_WRITABLE
2738 if (!LABEL_IS_SUN && g_partitions > 4) {
2739 delete_partition(ext_index);
2747 /* for fdisk -l: try all things in /proc/partitions
2748 that look like a partition name (do not end in a digit) */
2750 list_devs_in_proc_partititons(void)
2753 char line[100], ptname[100], devname[120], *s;
2756 procpt = fopen_or_warn("/proc/partitions", "r");
2758 while (fgets(line, sizeof(line), procpt)) {
2759 if (sscanf(line, " %d %d %d %[^\n ]",
2760 &ma, &mi, &sz, ptname) != 4)
2762 for (s = ptname; *s; s++)
2766 sprintf(devname, "/dev/%s", ptname);
2767 open_list_and_close(devname, 0);
2769 #if ENABLE_FEATURE_CLEAN_UP
2774 #if ENABLE_FEATURE_FDISK_WRITABLE
2776 unknown_command(int c)
2778 printf("%c: unknown command\n", c);
2782 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2783 int fdisk_main(int argc, char **argv)
2788 * fdisk -l [-b sectorsize] [-u] device ...
2789 * fdisk -s [partition] ...
2790 * fdisk [-b sectorsize] [-u] device
2792 * Options -C, -H, -S set the geometry.
2796 close_dev_fd(); /* needed: fd 3 must not stay closed */
2798 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2799 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2800 §or_size, &user_cylinders, &user_heads, &user_sectors);
2803 if (opt & OPT_b) { // -b
2804 /* Ugly: this sector size is really per device,
2805 so cannot be combined with multiple disks,
2806 and the same goes for the C/H/S options.
2808 if (sector_size != 512 && sector_size != 1024
2809 && sector_size != 2048)
2812 user_set_sector_size = 1;
2814 if (user_heads <= 0 || user_heads >= 256)
2816 if (user_sectors <= 0 || user_sectors >= 64)
2819 display_in_cyl_units = 0; // -u
2821 #if ENABLE_FEATURE_FDISK_WRITABLE
2828 open_list_and_close(*argv, 1);
2831 /* we don't have device names, */
2832 /* use /proc/partitions instead */
2833 list_devs_in_proc_partititons();
2836 #if ENABLE_FEATURE_FDISK_WRITABLE
2840 #if ENABLE_FEATURE_FDISK_BLKSIZE
2847 for (j = 0; j < argc; j++) {
2848 unsigned long long size;
2849 fd = xopen(argv[j], O_RDONLY);
2850 size = bb_BLKGETSIZE_sectors(fd) / 2;
2853 printf("%lld\n", size);
2855 printf("%s: %lld\n", argv[j], size);
2861 #if ENABLE_FEATURE_FDISK_WRITABLE
2865 disk_device = argv[0];
2866 get_boot(OPEN_MAIN);
2869 /* OSF label, and no DOS label */
2870 printf("Detected an OSF/1 disklabel on %s, entering "
2871 "disklabel mode\n", disk_device);
2873 /*Why do we do this? It seems to be counter-intuitive*/
2874 current_label_type = LABEL_DOS;
2875 /* If we return we may want to make an empty DOS label? */
2881 c = tolower(read_nonempty("Command (m for help): "));
2885 toggle_active(get_partition(1, g_partitions));
2886 else if (LABEL_IS_SUN)
2887 toggle_sunflags(get_partition(1, g_partitions),
2889 else if (LABEL_IS_SGI)
2890 sgi_set_bootpartition(
2891 get_partition(1, g_partitions));
2897 printf("\nThe current boot file is: %s\n",
2898 sgi_get_bootfile());
2899 if (read_maybe_empty("Please enter the name of the "
2900 "new boot file: ") == '\n')
2901 printf("Boot file unchanged\n");
2903 sgi_set_bootfile(line_ptr);
2905 #if ENABLE_FEATURE_OSF_LABEL
2912 toggle_dos_compatibility_flag();
2913 else if (LABEL_IS_SUN)
2914 toggle_sunflags(get_partition(1, g_partitions),
2916 else if (LABEL_IS_SGI)
2917 sgi_set_swappartition(
2918 get_partition(1, g_partitions));
2925 /* If sgi_label then don't use get_existing_partition,
2926 let the user select a partition, since
2927 get_existing_partition() only works for Linux-like
2929 if (!LABEL_IS_SGI) {
2930 j = get_existing_partition(1, g_partitions);
2932 j = get_partition(1, g_partitions);
2935 delete_partition(j);
2944 list_types(get_sys_types());
2959 if (ENABLE_FEATURE_CLEAN_UP)
2964 #if ENABLE_FEATURE_SUN_LABEL
2978 write_table(); /* does not return */
2980 #if ENABLE_FEATURE_FDISK_ADVANCED
2983 printf("\n\tSorry, no experts menu for SGI "
2984 "partition tables available\n\n");
2995 #endif /* FEATURE_FDISK_WRITABLE */