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)
19 #if !defined(BLKGETSIZE64)
20 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
25 # define inline_if_little_endian ALWAYS_INLINE
27 # define inline_if_little_endian /* nothing */
31 /* Looks like someone forgot to add this to config system */
32 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
33 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
34 # define IF_FEATURE_FDISK_BLKSIZE(a)
37 #define DEFAULT_SECTOR_SIZE 512
38 #define DEFAULT_SECTOR_SIZE_STR "512"
39 #define MAX_SECTOR_SIZE 2048
40 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
41 #define MAXIMUM_PARTS 60
43 #define ACTIVE_FLAG 0x80
46 #define WIN98_EXTENDED 0x0f
47 #define LINUX_PARTITION 0x81
48 #define LINUX_SWAP 0x82
49 #define LINUX_NATIVE 0x83
50 #define LINUX_EXTENDED 0x85
51 #define LINUX_LVM 0x8e
52 #define LINUX_RAID 0xfd
62 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
66 typedef unsigned long long ullong;
67 /* Used for sector numbers. Partition formats we know
68 * do not support more than 2^32 sectors
70 typedef uint32_t sector_t;
71 #if UINT_MAX == 4294967295
73 #elif ULONG_MAX == 4294967295
76 # error Cant detect sizeof(uint32_t)
81 unsigned char sectors;
82 unsigned short cylinders;
86 #define HDIO_GETGEO 0x0301 /* get device geometry */
88 static const char msg_building_new_label[] ALIGN1 =
89 "Building a new %s. Changes will remain in memory only,\n"
90 "until you decide to write them. After that the previous content\n"
91 "won't be recoverable.\n\n";
93 static const char msg_part_already_defined[] ALIGN1 =
94 "Partition %u is already defined, delete it before re-adding\n";
98 unsigned char boot_ind; /* 0x80 - active */
99 unsigned char head; /* starting head */
100 unsigned char sector; /* starting sector */
101 unsigned char cyl; /* starting cylinder */
102 unsigned char sys_ind; /* what partition type */
103 unsigned char end_head; /* end head */
104 unsigned char end_sector; /* end sector */
105 unsigned char end_cyl; /* end cylinder */
106 unsigned char start4[4]; /* starting sector counting from 0 */
107 unsigned char size4[4]; /* nr of sectors in partition */
110 static const char unable_to_open[] ALIGN1 = "can't open '%s'";
111 static const char unable_to_read[] ALIGN1 = "can't read from %s";
112 static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
115 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
118 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
120 #if ENABLE_FEATURE_SUN_LABEL
121 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
122 #define STATIC_SUN static
124 #define LABEL_IS_SUN 0
125 #define STATIC_SUN extern
128 #if ENABLE_FEATURE_SGI_LABEL
129 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
130 #define STATIC_SGI static
132 #define LABEL_IS_SGI 0
133 #define STATIC_SGI extern
136 #if ENABLE_FEATURE_AIX_LABEL
137 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
138 #define STATIC_AIX static
140 #define LABEL_IS_AIX 0
141 #define STATIC_AIX extern
144 #if ENABLE_FEATURE_OSF_LABEL
145 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
146 #define STATIC_OSF static
148 #define LABEL_IS_OSF 0
149 #define STATIC_OSF extern
152 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
154 static void update_units(void);
155 #if ENABLE_FEATURE_FDISK_WRITABLE
156 static void change_units(void);
157 static void reread_partition_table(int leave);
158 static void delete_partition(int i);
159 static unsigned get_partition(int warn, unsigned max);
160 static void list_types(const char *const *sys);
161 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
163 static const char *partition_type(unsigned char type);
164 static void get_geometry(void);
165 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
166 static int get_boot(enum action what);
168 static int get_boot(void);
174 static sector_t get_start_sect(const struct partition *p);
175 static sector_t get_nr_sects(const struct partition *p);
178 * per partition table entry data
180 * The four primary partitions have the same sectorbuffer (MBRbuffer)
181 * and have NULL ext_pointer.
182 * Each logical partition table entry has two pointers, one for the
183 * partition and one link to the next one.
186 struct partition *part_table; /* points into sectorbuffer */
187 struct partition *ext_pointer; /* points into sectorbuffer */
188 sector_t offset; /* disk sector number */
189 char *sectorbuffer; /* disk sector contents */
190 #if ENABLE_FEATURE_FDISK_WRITABLE
191 char changed; /* boolean */
195 /* DOS partition types */
197 static const char *const i386_sys_types[] = {
201 "\x05" "Extended", /* DOS 3.3+ extended partition */
202 "\x06" "FAT16", /* DOS 16-bit >=32M */
203 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
204 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
205 "\x0b" "Win95 FAT32",
206 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
207 "\x0e" "Win95 FAT16 (LBA)",
208 "\x0f" "Win95 Ext'd (LBA)",
209 "\x11" "Hidden FAT12",
210 "\x12" "Compaq diagnostics",
211 "\x14" "Hidden FAT16 <32M",
212 "\x16" "Hidden FAT16",
213 "\x17" "Hidden HPFS/NTFS",
214 "\x1b" "Hidden Win95 FAT32",
215 "\x1c" "Hidden W95 FAT32 (LBA)",
216 "\x1e" "Hidden W95 FAT16 (LBA)",
217 "\x3c" "Part.Magic recovery",
218 "\x41" "PPC PReP Boot",
220 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
221 "\x80" "Old Minix", /* Minix 1.4a and earlier */
222 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
223 "\x82" "Linux swap", /* also Solaris */
225 "\x84" "OS/2 hidden C: drive",
226 "\x85" "Linux extended",
227 "\x86" "NTFS volume set",
228 "\x87" "NTFS volume set",
230 "\x9f" "BSD/OS", /* BSDI */
231 "\xa0" "Thinkpad hibernation",
232 "\xa5" "FreeBSD", /* various BSD flavours */
236 "\xab" "Darwin boot",
239 "\xbe" "Solaris boot",
241 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
242 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
243 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
244 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
245 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
246 autodetect using persistent
248 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
251 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
252 "\x09" "AIX bootable", /* AIX data or Coherent */
254 "\x18" "AST SmartSleep",
257 "\x40" "Venix 80286",
259 "\x4e" "QNX4.x 2nd part",
260 "\x4f" "QNX4.x 3rd part",
262 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
263 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
264 "\x53" "OnTrack DM6 Aux3",
268 "\x5c" "Priam Edisk",
270 "\x64" "Novell Netware 286",
271 "\x65" "Novell Netware 386",
272 "\x70" "DiskSecure Multi-Boot",
275 "\x94" "Amoeba BBT", /* (bad block table) */
277 "\xbb" "Boot Wizard hidden",
278 "\xc1" "DRDOS/sec (FAT-12)",
279 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
280 "\xc6" "DRDOS/sec (FAT-16)",
282 "\xda" "Non-FS data",
283 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
284 Concurrent DOS or CTOS */
285 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
286 "\xdf" "BootIt", /* BootIt EMBRM */
287 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
288 extended partition */
289 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
290 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
291 partition < 1024 cyl. */
293 "\xf4" "SpeedStor", /* SpeedStor large partition */
294 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
295 "\xff" "BBT", /* Xenix Bad Block Table */
301 dev_fd = 3 /* the disk */
308 const char *disk_device;
309 int g_partitions; // = 4; /* maximum partition + 1 */
310 unsigned units_per_sector; // = 1;
311 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
312 unsigned user_set_sector_size;
313 unsigned sector_offset; // = 1;
314 unsigned g_heads, g_sectors, g_cylinders;
315 smallint /* enum label_type */ current_label_type;
316 smallint display_in_cyl_units; // = 1;
317 #if ENABLE_FEATURE_OSF_LABEL
318 smallint possibly_osf_label;
321 smallint listing; /* no aborts for fdisk -l */
322 smallint dos_compatible_flag; // = 1;
323 #if ENABLE_FEATURE_FDISK_WRITABLE
325 smallint nowarn; /* no warnings for fdisk -l/-s */
327 int ext_index; /* the prime extended partition */
328 unsigned user_cylinders, user_heads, user_sectors;
329 unsigned pt_heads, pt_sectors;
330 unsigned kern_heads, kern_sectors;
331 sector_t extended_offset; /* offset of link pointers */
332 sector_t total_number_of_sectors;
335 char line_buffer[80];
336 char partname_buffer[80];
337 /* Raw disk label. For DOS-type partition tables the MBR,
338 * with descriptions of the primary partitions. */
339 char MBRbuffer[MAX_SECTOR_SIZE];
340 /* Partition tables */
341 struct pte ptes[MAXIMUM_PARTS];
343 #define G (*ptr_to_globals)
344 #define line_ptr (G.line_ptr )
345 #define disk_device (G.disk_device )
346 #define g_partitions (G.g_partitions )
347 #define units_per_sector (G.units_per_sector )
348 #define sector_size (G.sector_size )
349 #define user_set_sector_size (G.user_set_sector_size)
350 #define sector_offset (G.sector_offset )
351 #define g_heads (G.g_heads )
352 #define g_sectors (G.g_sectors )
353 #define g_cylinders (G.g_cylinders )
354 #define current_label_type (G.current_label_type )
355 #define display_in_cyl_units (G.display_in_cyl_units)
356 #define possibly_osf_label (G.possibly_osf_label )
357 #define listing (G.listing )
358 #define dos_compatible_flag (G.dos_compatible_flag )
359 #define nowarn (G.nowarn )
360 #define ext_index (G.ext_index )
361 #define user_cylinders (G.user_cylinders )
362 #define user_heads (G.user_heads )
363 #define user_sectors (G.user_sectors )
364 #define pt_heads (G.pt_heads )
365 #define pt_sectors (G.pt_sectors )
366 #define kern_heads (G.kern_heads )
367 #define kern_sectors (G.kern_sectors )
368 #define extended_offset (G.extended_offset )
369 #define total_number_of_sectors (G.total_number_of_sectors)
370 #define listingbuf (G.listingbuf )
371 #define line_buffer (G.line_buffer )
372 #define partname_buffer (G.partname_buffer)
373 #define MBRbuffer (G.MBRbuffer )
374 #define ptes (G.ptes )
375 #define INIT_G() do { \
376 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
377 sector_size = DEFAULT_SECTOR_SIZE; \
380 display_in_cyl_units = 1; \
381 units_per_sector = 1; \
382 dos_compatible_flag = 1; \
386 /* TODO: move to libbb? */
387 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
388 * disks > 2^32 sectors
390 static sector_t bb_BLKGETSIZE_sectors(int fd)
393 unsigned long longsectors;
395 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
396 /* Got bytes, convert to 512 byte sectors */
398 if (v64 != (sector_t)v64) {
400 /* Not only DOS, but all other partition tables
401 * we support can't record more than 32 bit
402 * sector counts or offsets
404 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
409 /* Needs temp of type long */
410 if (ioctl(fd, BLKGETSIZE, &longsectors))
412 if (sizeof(long) > sizeof(sector_t)
413 && longsectors != (sector_t)longsectors
421 #define IS_EXTENDED(i) \
422 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
424 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
426 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
428 #define pt_offset(b, n) \
429 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
431 #define sector(s) ((s) & 0x3f)
433 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
435 #define hsc2sector(h,s,c) \
436 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
438 #define set_hsc(h,s,c,sector) \
440 s = sector % g_sectors + 1; \
441 sector /= g_sectors; \
442 h = sector % g_heads; \
445 s |= (sector >> 2) & 0xc0; \
451 /* Not really closing, but making sure it is open, and to harmless place */
452 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
456 * Return partition name - uses static storage
459 partname(const char *dev, int pno, int lth)
466 bufp = partname_buffer;
467 bufsiz = sizeof(partname_buffer);
472 if (isdigit(dev[w-1]))
475 /* devfs kludge - note: fdisk partition names are not supposed
476 to equal kernel names, so there is no reason to do this */
477 if (strcmp(dev + w - 4, "disc") == 0) {
485 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
486 lth-wp-2, w, dev, p, pno);
488 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
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 static void fdisk_fatal(const char *why)
517 longjmp(listingbuf, 1);
519 bb_error_msg_and_die(why, disk_device);
523 seek_sector(sector_t secno)
525 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
526 off64_t off = (off64_t)secno * sector_size;
527 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
528 fdisk_fatal(unable_to_seek);
530 uint64_t off = (uint64_t)secno * sector_size;
531 if (off > MAXINT(off_t)
532 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
534 fdisk_fatal(unable_to_seek);
539 #if ENABLE_FEATURE_FDISK_WRITABLE
540 /* Read line; return 0 or first printable char */
542 read_line(const char *prompt)
546 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
548 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
550 if (line_buffer[sz-1] == '\n')
551 line_buffer[--sz] = '\0';
553 line_ptr = line_buffer;
554 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
560 set_all_unchanged(void)
564 for (i = 0; i < MAXIMUM_PARTS; i++)
568 static ALWAYS_INLINE void
574 static ALWAYS_INLINE void
575 write_part_table_flag(char *b)
582 read_nonempty(const char *mesg)
584 while (!read_line(mesg))
590 read_maybe_empty(const char *mesg)
592 if (!read_line(mesg)) {
593 line_ptr = line_buffer;
601 read_hex(const char *const *sys)
605 read_nonempty("Hex code (type L to list codes): ");
606 if (*line_ptr == 'l' || *line_ptr == 'L') {
610 v = bb_strtoul(line_ptr, NULL, 16);
617 write_sector(sector_t secno, const void *buf)
620 xwrite(dev_fd, buf, sector_size);
622 #endif /* FEATURE_FDISK_WRITABLE */
625 #include "fdisk_aix.c"
627 struct sun_partition {
628 unsigned char info[128]; /* Informative text string */
629 unsigned char spare0[14];
631 unsigned char spare1;
633 unsigned char spare2;
636 unsigned char spare1[246]; /* Boot information etc. */
637 unsigned short rspeed; /* Disk rotational speed */
638 unsigned short pcylcount; /* Physical cylinder count */
639 unsigned short sparecyl; /* extra sects per cylinder */
640 unsigned char spare2[4]; /* More magic... */
641 unsigned short ilfact; /* Interleave factor */
642 unsigned short ncyl; /* Data cylinder count */
643 unsigned short nacyl; /* Alt. cylinder count */
644 unsigned short ntrks; /* Tracks per cylinder */
645 unsigned short nsect; /* Sectors per track */
646 unsigned char spare3[4]; /* Even more magic... */
647 struct sun_partinfo {
648 uint32_t start_cylinder;
649 uint32_t num_sectors;
651 unsigned short magic; /* Magic number */
652 unsigned short csum; /* Label xor'd checksum */
654 typedef struct sun_partition sun_partition;
655 #define sunlabel ((sun_partition *)MBRbuffer)
656 STATIC_OSF void bsd_select(void);
657 STATIC_OSF void xbsd_print_disklabel(int);
658 #include "fdisk_osf.c"
660 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
662 fdisk_swap16(uint16_t x)
664 return (x << 8) | (x >> 8);
668 fdisk_swap32(uint32_t x)
671 ((x & 0xFF00) << 8) |
672 ((x & 0xFF0000) >> 8) |
677 STATIC_SGI const char *const sgi_sys_types[];
678 STATIC_SGI unsigned sgi_get_num_sectors(int i);
679 STATIC_SGI int sgi_get_sysid(int i);
680 STATIC_SGI void sgi_delete_partition(int i);
681 STATIC_SGI void sgi_change_sysid(int i, int sys);
682 STATIC_SGI void sgi_list_table(int xtra);
683 #if ENABLE_FEATURE_FDISK_ADVANCED
684 STATIC_SGI void sgi_set_xcyl(void);
686 STATIC_SGI int verify_sgi(int verbose);
687 STATIC_SGI void sgi_add_partition(int n, int sys);
688 STATIC_SGI void sgi_set_swappartition(int i);
689 STATIC_SGI const char *sgi_get_bootfile(void);
690 STATIC_SGI void sgi_set_bootfile(const char* aFile);
691 STATIC_SGI void create_sgiinfo(void);
692 STATIC_SGI void sgi_write_table(void);
693 STATIC_SGI void sgi_set_bootpartition(int i);
694 #include "fdisk_sgi.c"
696 STATIC_SUN const char *const sun_sys_types[];
697 STATIC_SUN void sun_delete_partition(int i);
698 STATIC_SUN void sun_change_sysid(int i, int sys);
699 STATIC_SUN void sun_list_table(int xtra);
700 STATIC_SUN void add_sun_partition(int n, int sys);
701 #if ENABLE_FEATURE_FDISK_ADVANCED
702 STATIC_SUN void sun_set_alt_cyl(void);
703 STATIC_SUN void sun_set_ncyl(int cyl);
704 STATIC_SUN void sun_set_xcyl(void);
705 STATIC_SUN void sun_set_ilfact(void);
706 STATIC_SUN void sun_set_rspeed(void);
707 STATIC_SUN void sun_set_pcylcount(void);
709 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
710 STATIC_SUN void verify_sun(void);
711 STATIC_SUN void sun_write_table(void);
712 #include "fdisk_sun.c"
715 static inline_if_little_endian unsigned
716 read4_little_endian(const unsigned char *cp)
719 move_from_unaligned32(v, cp);
724 get_start_sect(const struct partition *p)
726 return read4_little_endian(p->start4);
730 get_nr_sects(const struct partition *p)
732 return read4_little_endian(p->size4);
735 #if ENABLE_FEATURE_FDISK_WRITABLE
736 /* start_sect and nr_sects are stored little endian on all machines */
737 /* moreover, they are not aligned correctly */
738 static inline_if_little_endian void
739 store4_little_endian(unsigned char *cp, unsigned val)
741 uint32_t v = SWAP_LE32(val);
742 move_to_unaligned32(cp, v);
746 set_start_sect(struct partition *p, unsigned start_sect)
748 store4_little_endian(p->start4, start_sect);
752 set_nr_sects(struct partition *p, unsigned nr_sects)
754 store4_little_endian(p->size4, nr_sects);
758 /* Allocate a buffer and read a partition table sector */
760 read_pte(struct pte *pe, sector_t offset)
763 pe->sectorbuffer = xzalloc(sector_size);
765 /* xread would make us abort - bad for fdisk -l */
766 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
767 fdisk_fatal(unable_to_read);
768 #if ENABLE_FEATURE_FDISK_WRITABLE
771 pe->part_table = pe->ext_pointer = NULL;
775 get_partition_start(const struct pte *pe)
777 return pe->offset + get_start_sect(pe->part_table);
780 #if ENABLE_FEATURE_FDISK_WRITABLE
782 * Avoid warning about DOS partitions when no DOS partition was changed.
783 * Here a heuristic "is probably dos partition".
784 * We might also do the opposite and warn in all cases except
785 * for "is probably nondos partition".
789 is_dos_partition(int t)
791 return (t == 1 || t == 4 || t == 6 ||
792 t == 0x0b || t == 0x0c || t == 0x0e ||
793 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
794 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
795 t == 0xc1 || t == 0xc4 || t == 0xc6);
802 puts("Command Action");
804 puts("a\ttoggle a read only flag"); /* sun */
805 puts("b\tedit bsd disklabel");
806 puts("c\ttoggle the mountable flag"); /* sun */
807 puts("d\tdelete a partition");
808 puts("l\tlist known partition types");
809 puts("n\tadd a new partition");
810 puts("o\tcreate a new empty DOS partition table");
811 puts("p\tprint the partition table");
812 puts("q\tquit without saving changes");
813 puts("s\tcreate a new empty Sun disklabel"); /* sun */
814 puts("t\tchange a partition's system id");
815 puts("u\tchange display/entry units");
816 puts("v\tverify the partition table");
817 puts("w\twrite table to disk and exit");
818 #if ENABLE_FEATURE_FDISK_ADVANCED
819 puts("x\textra functionality (experts only)");
821 } else if (LABEL_IS_SGI) {
822 puts("a\tselect bootable partition"); /* sgi flavour */
823 puts("b\tedit bootfile entry"); /* sgi */
824 puts("c\tselect sgi swap partition"); /* sgi flavour */
825 puts("d\tdelete a partition");
826 puts("l\tlist known partition types");
827 puts("n\tadd a new partition");
828 puts("o\tcreate a new empty DOS partition table");
829 puts("p\tprint the partition table");
830 puts("q\tquit without saving changes");
831 puts("s\tcreate a new empty Sun disklabel"); /* sun */
832 puts("t\tchange a partition's system id");
833 puts("u\tchange display/entry units");
834 puts("v\tverify the partition table");
835 puts("w\twrite table to disk and exit");
836 } else if (LABEL_IS_AIX) {
837 puts("o\tcreate a new empty DOS partition table");
838 puts("q\tquit without saving changes");
839 puts("s\tcreate a new empty Sun disklabel"); /* sun */
841 puts("a\ttoggle a bootable flag");
842 puts("b\tedit bsd disklabel");
843 puts("c\ttoggle the dos compatibility flag");
844 puts("d\tdelete a partition");
845 puts("l\tlist known partition types");
846 puts("n\tadd a new partition");
847 puts("o\tcreate a new empty DOS partition table");
848 puts("p\tprint the partition table");
849 puts("q\tquit without saving changes");
850 puts("s\tcreate a new empty Sun disklabel"); /* sun */
851 puts("t\tchange a partition's system id");
852 puts("u\tchange display/entry units");
853 puts("v\tverify the partition table");
854 puts("w\twrite table to disk and exit");
855 #if ENABLE_FEATURE_FDISK_ADVANCED
856 puts("x\textra functionality (experts only)");
860 #endif /* FEATURE_FDISK_WRITABLE */
863 #if ENABLE_FEATURE_FDISK_ADVANCED
867 puts("Command Action");
869 puts("a\tchange number of alternate cylinders"); /*sun*/
870 puts("c\tchange number of cylinders");
871 puts("d\tprint the raw data in the partition table");
872 puts("e\tchange number of extra sectors per cylinder");/*sun*/
873 puts("h\tchange number of heads");
874 puts("i\tchange interleave factor"); /*sun*/
875 puts("o\tchange rotation speed (rpm)"); /*sun*/
876 puts("p\tprint the partition table");
877 puts("q\tquit without saving changes");
878 puts("r\treturn to main menu");
879 puts("s\tchange number of sectors/track");
880 puts("v\tverify the partition table");
881 puts("w\twrite table to disk and exit");
882 puts("y\tchange number of physical cylinders"); /*sun*/
883 } else if (LABEL_IS_SGI) {
884 puts("b\tmove beginning of data in a partition"); /* !sun */
885 puts("c\tchange number of cylinders");
886 puts("d\tprint the raw data in the partition table");
887 puts("e\tlist extended partitions"); /* !sun */
888 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
889 puts("h\tchange number of heads");
890 puts("p\tprint the partition table");
891 puts("q\tquit without saving changes");
892 puts("r\treturn to main menu");
893 puts("s\tchange number of sectors/track");
894 puts("v\tverify the partition table");
895 puts("w\twrite table to disk and exit");
896 } else if (LABEL_IS_AIX) {
897 puts("b\tmove beginning of data in a partition"); /* !sun */
898 puts("c\tchange number of cylinders");
899 puts("d\tprint the raw data in the partition table");
900 puts("e\tlist extended partitions"); /* !sun */
901 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
902 puts("h\tchange number of heads");
903 puts("p\tprint the partition table");
904 puts("q\tquit without saving changes");
905 puts("r\treturn to main menu");
906 puts("s\tchange number of sectors/track");
907 puts("v\tverify the partition table");
908 puts("w\twrite table to disk and exit");
910 puts("b\tmove beginning of data in a partition"); /* !sun */
911 puts("c\tchange number of cylinders");
912 puts("d\tprint the raw data in the partition table");
913 puts("e\tlist extended partitions"); /* !sun */
914 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
915 #if ENABLE_FEATURE_SGI_LABEL
916 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
918 puts("h\tchange number of heads");
919 puts("p\tprint the partition table");
920 puts("q\tquit without saving changes");
921 puts("r\treturn to main menu");
922 puts("s\tchange number of sectors/track");
923 puts("v\tverify the partition table");
924 puts("w\twrite table to disk and exit");
927 #endif /* ADVANCED mode */
929 #if ENABLE_FEATURE_FDISK_WRITABLE
930 static const char *const *
934 LABEL_IS_SUN ? sun_sys_types :
935 LABEL_IS_SGI ? sgi_sys_types :
939 #define get_sys_types() i386_sys_types
943 partition_type(unsigned char type)
946 const char *const *types = get_sys_types();
948 for (i = 0; types[i]; i++)
949 if ((unsigned char)types[i][0] == type)
956 is_cleared_partition(const struct partition *p)
958 /* We consider partition "cleared" only if it has only zeros */
959 const char *cp = (const char *)p;
960 int cnt = sizeof(*p);
968 clear_partition(struct partition *p)
971 memset(p, 0, sizeof(*p));
974 #if ENABLE_FEATURE_FDISK_WRITABLE
978 return LABEL_IS_SUN ? sunlabel->infos[i].id :
979 (LABEL_IS_SGI ? sgi_get_sysid(i) :
980 ptes[i].part_table->sys_ind);
984 list_types(const char *const *sys)
989 unsigned done, next, size;
992 for (size = 0; sys[size]; size++)
996 for (i = COLS-1; i >= 0; i--) {
997 done += (size + i - done) / (i + 1);
998 last[COLS-1 - i] = done;
1001 i = done = next = 0;
1003 printf("%c%2x %-22.22s", i ? ' ' : '\n',
1004 (unsigned char)sys[next][0],
1006 next = last[i++] + done;
1007 if (i >= COLS || next >= last[i]) {
1011 } while (done < last[0]);
1016 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1018 struct partition *p;
1022 p = ptes[i].ext_pointer;
1023 offset = extended_offset;
1025 p = ptes[i].part_table;
1026 offset = ptes[i].offset;
1030 set_start_sect(p, start - offset);
1031 set_nr_sects(p, stop - start + 1);
1032 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1033 start = g_heads * g_sectors * 1024 - 1;
1034 set_hsc(p->head, p->sector, p->cyl, start);
1035 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1036 stop = g_heads * g_sectors * 1024 - 1;
1037 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1038 ptes[i].changed = 1;
1045 if (g_heads && g_sectors && g_cylinders)
1048 printf("Unknown value(s) for:");
1054 printf(" cylinders");
1056 #if ENABLE_FEATURE_FDISK_WRITABLE
1057 " (settable in the extra functions menu)"
1066 int cyl_units = g_heads * g_sectors;
1068 if (display_in_cyl_units && cyl_units)
1069 units_per_sector = cyl_units;
1071 units_per_sector = 1; /* in sectors */
1074 #if ENABLE_FEATURE_FDISK_WRITABLE
1076 warn_cylinders(void)
1078 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1080 "The number of cylinders for this disk is set to %u.\n"
1081 "There is nothing wrong with that, but this is larger than 1024,\n"
1082 "and could in certain setups cause problems with:\n"
1083 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1084 "2) booting and partitioning software from other OSs\n"
1085 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1091 read_extended(int ext)
1095 struct partition *p, *q;
1099 pex->ext_pointer = pex->part_table;
1101 p = pex->part_table;
1102 if (!get_start_sect(p)) {
1103 printf("Bad offset in primary extended partition\n");
1107 while (IS_EXTENDED(p->sys_ind)) {
1108 struct pte *pe = &ptes[g_partitions];
1110 if (g_partitions >= MAXIMUM_PARTS) {
1111 /* This is not a Linux restriction, but
1112 this program uses arrays of size MAXIMUM_PARTS.
1113 Do not try to 'improve' this test. */
1114 struct pte *pre = &ptes[g_partitions - 1];
1115 #if ENABLE_FEATURE_FDISK_WRITABLE
1116 printf("Warning: deleting partitions after %u\n",
1120 clear_partition(pre->ext_pointer);
1124 read_pte(pe, extended_offset + get_start_sect(p));
1126 if (!extended_offset)
1127 extended_offset = get_start_sect(p);
1129 q = p = pt_offset(pe->sectorbuffer, 0);
1130 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1131 if (IS_EXTENDED(p->sys_ind)) {
1132 if (pe->ext_pointer)
1133 printf("Warning: extra link "
1134 "pointer in partition table"
1135 " %u\n", g_partitions + 1);
1137 pe->ext_pointer = p;
1138 } else if (p->sys_ind) {
1140 printf("Warning: ignoring extra "
1141 "data in partition table"
1142 " %u\n", g_partitions + 1);
1148 /* very strange code here... */
1149 if (!pe->part_table) {
1150 if (q != pe->ext_pointer)
1153 pe->part_table = q + 1;
1155 if (!pe->ext_pointer) {
1156 if (q != pe->part_table)
1157 pe->ext_pointer = q;
1159 pe->ext_pointer = q + 1;
1162 p = pe->ext_pointer;
1166 #if ENABLE_FEATURE_FDISK_WRITABLE
1167 /* remove empty links */
1169 for (i = 4; i < g_partitions; i++) {
1170 struct pte *pe = &ptes[i];
1172 if (!get_nr_sects(pe->part_table)
1173 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1175 printf("Omitting empty partition (%u)\n", i+1);
1176 delete_partition(i);
1177 goto remove; /* numbering changed */
1183 #if ENABLE_FEATURE_FDISK_WRITABLE
1185 create_doslabel(void)
1187 printf(msg_building_new_label, "DOS disklabel");
1189 current_label_type = LABEL_DOS;
1190 #if ENABLE_FEATURE_OSF_LABEL
1191 possibly_osf_label = 0;
1195 memset(&MBRbuffer[510 - 4*16], 0, 4*16);
1196 write_part_table_flag(MBRbuffer);
1197 extended_offset = 0;
1198 set_all_unchanged();
1200 get_boot(CREATE_EMPTY_DOS);
1205 get_sectorsize(void)
1207 if (!user_set_sector_size) {
1209 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1211 if (sector_size != DEFAULT_SECTOR_SIZE)
1212 printf("Note: sector size is %u "
1213 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1219 get_kernel_geometry(void)
1221 struct hd_geometry geometry;
1223 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1224 kern_heads = geometry.heads;
1225 kern_sectors = geometry.sectors;
1226 /* never use geometry.cylinders - it is truncated */
1231 get_partition_table_geometry(void)
1233 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1234 struct partition *p;
1235 int i, h, s, hh, ss;
1239 if (!(valid_part_table_flag((char*)bufp)))
1243 for (i = 0; i < 4; i++) {
1244 p = pt_offset(bufp, i);
1245 if (p->sys_ind != 0) {
1246 h = p->end_head + 1;
1247 s = (p->end_sector & 077);
1252 } else if (hh != h || ss != s)
1257 if (!first && !bad) {
1269 sec_fac = sector_size / 512;
1270 #if ENABLE_FEATURE_SUN_LABEL
1271 guess_device_type();
1273 g_heads = g_cylinders = g_sectors = 0;
1274 kern_heads = kern_sectors = 0;
1275 pt_heads = pt_sectors = 0;
1277 get_kernel_geometry();
1278 get_partition_table_geometry();
1280 g_heads = user_heads ? user_heads :
1281 pt_heads ? pt_heads :
1282 kern_heads ? kern_heads : 255;
1283 g_sectors = user_sectors ? user_sectors :
1284 pt_sectors ? pt_sectors :
1285 kern_sectors ? kern_sectors : 63;
1286 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1289 if (dos_compatible_flag)
1290 sector_offset = g_sectors;
1292 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1294 g_cylinders = user_cylinders;
1298 * Opens disk_device and optionally reads MBR.
1299 * FIXME: document what each 'what' value will do!
1301 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1302 * 0: found or created label
1305 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1306 static int get_boot(enum action what)
1308 static int get_boot(void)
1309 #define get_boot(what) get_boot()
1315 for (i = 0; i < 4; i++) {
1316 struct pte *pe = &ptes[i];
1317 pe->part_table = pt_offset(MBRbuffer, i);
1318 pe->ext_pointer = NULL;
1320 pe->sectorbuffer = MBRbuffer;
1321 #if ENABLE_FEATURE_FDISK_WRITABLE
1322 pe->changed = (what == CREATE_EMPTY_DOS);
1326 #if ENABLE_FEATURE_FDISK_WRITABLE
1327 // ALERT! highly idiotic design!
1328 // We end up here when we call get_boot() recursively
1329 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1330 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1331 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1332 // So skip opening device _again_...
1333 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1336 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1339 fd = open(disk_device, O_RDONLY);
1341 if (what == TRY_ONLY)
1343 fdisk_fatal(unable_to_open);
1345 printf("'%s' is opened for read only\n", disk_device);
1347 xmove_fd(fd, dev_fd);
1348 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1349 if (what == TRY_ONLY) {
1353 fdisk_fatal(unable_to_read);
1356 fd = open(disk_device, O_RDONLY);
1359 if (512 != full_read(fd, MBRbuffer, 512)) {
1363 xmove_fd(fd, dev_fd);
1369 #if ENABLE_FEATURE_SUN_LABEL
1370 if (check_sun_label())
1373 #if ENABLE_FEATURE_SGI_LABEL
1374 if (check_sgi_label())
1377 #if ENABLE_FEATURE_AIX_LABEL
1378 if (check_aix_label())
1381 #if ENABLE_FEATURE_OSF_LABEL
1382 if (check_osf_label()) {
1383 possibly_osf_label = 1;
1384 if (!valid_part_table_flag(MBRbuffer)) {
1385 current_label_type = LABEL_OSF;
1388 printf("This disk has both DOS and BSD magic.\n"
1389 "Give the 'b' command to go to BSD mode.\n");
1393 #if !ENABLE_FEATURE_FDISK_WRITABLE
1394 if (!valid_part_table_flag(MBRbuffer))
1397 if (!valid_part_table_flag(MBRbuffer)) {
1398 if (what == OPEN_MAIN) {
1399 printf("Device contains neither a valid DOS "
1400 "partition table, nor Sun, SGI or OSF "
1403 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1413 #endif /* FEATURE_FDISK_WRITABLE */
1416 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1419 for (i = 0; i < 4; i++) {
1420 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1421 if (g_partitions != 4)
1422 printf("Ignoring extra extended "
1423 "partition %u\n", i + 1);
1429 for (i = 3; i < g_partitions; i++) {
1430 struct pte *pe = &ptes[i];
1431 if (!valid_part_table_flag(pe->sectorbuffer)) {
1432 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1433 "table %u will be corrected by w(rite)\n",
1434 pe->sectorbuffer[510],
1435 pe->sectorbuffer[511],
1437 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1444 #if ENABLE_FEATURE_FDISK_WRITABLE
1446 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1447 * If the user hits Enter, DFLT is returned.
1448 * Answers like +10 are interpreted as offsets from BASE.
1450 * There is no default if DFLT is not between LOW and HIGH.
1453 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1457 const char *fmt = "%s (%u-%u, default %u): ";
1459 if (dflt < low || dflt > high) {
1460 fmt = "%s (%u-%u): ";
1465 int use_default = default_ok;
1467 /* ask question and read answer */
1469 printf(fmt, mesg, low, high, dflt);
1470 read_maybe_empty("");
1471 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1472 && *line_ptr != '-' && *line_ptr != '+');
1474 if (*line_ptr == '+' || *line_ptr == '-') {
1475 int minus = (*line_ptr == '-');
1478 value = atoi(line_ptr + 1);
1480 /* (1) if 2nd char is digit, use_default = 0.
1481 * (2) move line_ptr to first non-digit. */
1482 while (isdigit(*++line_ptr))
1485 switch (*line_ptr) {
1488 if (!display_in_cyl_units)
1489 value *= g_heads * g_sectors;
1503 absolute = 1000000000;
1512 bytes = (ullong) value * absolute;
1513 unit = sector_size * units_per_sector;
1514 bytes += unit/2; /* round */
1522 value = atoi(line_ptr);
1523 while (isdigit(*line_ptr)) {
1530 printf("Using default value %u\n", value);
1532 if (value >= low && value <= high)
1534 printf("Value is out of range\n");
1540 get_partition(int warn, unsigned max)
1545 i = read_int(1, 0, max, 0, "Partition number") - 1;
1549 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1550 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1551 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1553 printf("Warning: partition %u has empty type\n", i+1);
1560 get_existing_partition(int warn, unsigned max)
1565 for (i = 0; i < max; i++) {
1566 struct pte *pe = &ptes[i];
1567 struct partition *p = pe->part_table;
1569 if (p && !is_cleared_partition(p)) {
1576 printf("Selected partition %u\n", pno+1);
1579 printf("No partition is defined yet!\n");
1583 return get_partition(warn, max);
1587 get_nonexisting_partition(int warn, unsigned max)
1592 for (i = 0; i < max; i++) {
1593 struct pte *pe = &ptes[i];
1594 struct partition *p = pe->part_table;
1596 if (p && is_cleared_partition(p)) {
1603 printf("Selected partition %u\n", pno+1);
1606 printf("All primary partitions have been defined already!\n");
1610 return get_partition(warn, max);
1617 display_in_cyl_units = !display_in_cyl_units;
1619 printf("Changing display/entry units to %s\n",
1624 toggle_active(int i)
1626 struct pte *pe = &ptes[i];
1627 struct partition *p = pe->part_table;
1629 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1630 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1631 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1636 toggle_dos_compatibility_flag(void)
1638 dos_compatible_flag = 1 - dos_compatible_flag;
1639 if (dos_compatible_flag) {
1640 sector_offset = g_sectors;
1641 printf("DOS Compatibility flag is set\n");
1644 printf("DOS Compatibility flag is not set\n");
1649 delete_partition(int i)
1651 struct pte *pe = &ptes[i];
1652 struct partition *p = pe->part_table;
1653 struct partition *q = pe->ext_pointer;
1655 /* Note that for the fifth partition (i == 4) we don't actually
1656 * decrement partitions.
1659 if (warn_geometry())
1660 return; /* C/H/S not set */
1664 sun_delete_partition(i);
1668 sgi_delete_partition(i);
1673 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1675 ptes[ext_index].ext_pointer = NULL;
1676 extended_offset = 0;
1682 if (!q->sys_ind && i > 4) {
1683 /* the last one in the chain - just delete */
1686 clear_partition(ptes[i].ext_pointer);
1687 ptes[i].changed = 1;
1689 /* not the last one - further ones will be moved down */
1691 /* delete this link in the chain */
1692 p = ptes[i-1].ext_pointer;
1694 set_start_sect(p, get_start_sect(q));
1695 set_nr_sects(p, get_nr_sects(q));
1696 ptes[i-1].changed = 1;
1697 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1698 /* the first logical in a longer chain */
1701 if (pe->part_table) /* prevent SEGFAULT */
1702 set_start_sect(pe->part_table,
1703 get_partition_start(pe) -
1705 pe->offset = extended_offset;
1709 if (g_partitions > 5) {
1711 while (i < g_partitions) {
1712 ptes[i] = ptes[i+1];
1716 /* the only logical: clear only */
1717 clear_partition(ptes[i].part_table);
1725 int i, sys, origsys;
1726 struct partition *p;
1728 /* If sgi_label then don't use get_existing_partition,
1729 let the user select a partition, since get_existing_partition()
1730 only works for Linux like partition tables. */
1731 if (!LABEL_IS_SGI) {
1732 i = get_existing_partition(0, g_partitions);
1734 i = get_partition(0, g_partitions);
1738 p = ptes[i].part_table;
1739 origsys = sys = get_sysid(i);
1741 /* if changing types T to 0 is allowed, then
1742 the reverse change must be allowed, too */
1743 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1744 printf("Partition %u does not exist yet!\n", i + 1);
1748 sys = read_hex(get_sys_types());
1750 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1751 printf("Type 0 means free space to many systems\n"
1752 "(but not to Linux). Having partitions of\n"
1753 "type 0 is probably unwise.\n");
1757 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1758 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1759 printf("You cannot change a partition into"
1760 " an extended one or vice versa\n");
1766 #if ENABLE_FEATURE_SUN_LABEL
1767 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1768 printf("Consider leaving partition 3 "
1769 "as Whole disk (5),\n"
1770 "as SunOS/Solaris expects it and "
1771 "even Linux likes it\n\n");
1773 #if ENABLE_FEATURE_SGI_LABEL
1776 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1777 (i == 8 && sys != 0)
1780 printf("Consider leaving partition 9 "
1781 "as volume header (0),\nand "
1782 "partition 11 as entire volume (6)"
1783 "as IRIX expects it\n\n");
1789 sun_change_sysid(i, sys);
1790 } else if (LABEL_IS_SGI) {
1791 sgi_change_sysid(i, sys);
1795 printf("Changed system type of partition %u "
1796 "to %x (%s)\n", i + 1, sys,
1797 partition_type(sys));
1798 ptes[i].changed = 1;
1799 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1805 #endif /* FEATURE_FDISK_WRITABLE */
1808 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1809 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1810 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1811 * Lubkin Oct. 1991). */
1814 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1816 int spc = g_heads * g_sectors;
1820 *h = ls / g_sectors;
1821 *s = ls % g_sectors + 1; /* sectors count from 1 */
1825 check_consistency(const struct partition *p, int partition)
1827 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1828 unsigned pec, peh, pes; /* physical ending c, h, s */
1829 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1830 unsigned lec, leh, les; /* logical ending c, h, s */
1832 if (!g_heads || !g_sectors || (partition >= 4))
1833 return; /* do not check extended partitions */
1835 /* physical beginning c, h, s */
1836 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1838 pbs = p->sector & 0x3f;
1840 /* physical ending c, h, s */
1841 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1843 pes = p->end_sector & 0x3f;
1845 /* compute logical beginning (c, h, s) */
1846 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1848 /* compute logical ending (c, h, s) */
1849 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1851 /* Same physical / logical beginning? */
1852 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1853 printf("Partition %u has different physical/logical "
1854 "beginnings (non-Linux?):\n", partition + 1);
1855 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
1856 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
1859 /* Same physical / logical ending? */
1860 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1861 printf("Partition %u has different physical/logical "
1862 "endings:\n", partition + 1);
1863 printf(" phys=(%u, %u, %u) ", pec, peh, pes);
1864 printf("logical=(%u, %u, %u)\n", lec, leh, les);
1867 /* Ending on cylinder boundary? */
1868 if (peh != (g_heads - 1) || pes != g_sectors) {
1869 printf("Partition %u does not end on cylinder boundary\n",
1875 list_disk_geometry(void)
1877 ullong bytes = ((ullong)total_number_of_sectors << 9);
1878 long megabytes = bytes / 1000000;
1880 if (megabytes < 10000)
1881 printf("\nDisk %s: %lu MB, %llu bytes\n",
1882 disk_device, megabytes, bytes);
1884 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1885 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1886 printf("%u heads, %u sectors/track, %u cylinders",
1887 g_heads, g_sectors, g_cylinders);
1888 if (units_per_sector == 1)
1889 printf(", total %"SECT_FMT"u sectors",
1890 total_number_of_sectors / (sector_size/512));
1891 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1893 units_per_sector, sector_size, units_per_sector * sector_size);
1897 * Check whether partition entries are ordered by their starting positions.
1898 * Return 0 if OK. Return i if partition i should have been earlier.
1899 * Two separate checks: primary and logical partitions.
1902 wrong_p_order(int *prev)
1904 const struct pte *pe;
1905 const struct partition *p;
1906 sector_t last_p_start_pos = 0, p_start_pos;
1907 unsigned i, last_i = 0;
1909 for (i = 0; i < g_partitions; i++) {
1912 last_p_start_pos = 0;
1917 p_start_pos = get_partition_start(pe);
1919 if (last_p_start_pos > p_start_pos) {
1925 last_p_start_pos = p_start_pos;
1932 #if ENABLE_FEATURE_FDISK_ADVANCED
1934 * Fix the chain of logicals.
1935 * extended_offset is unchanged, the set of sectors used is unchanged
1936 * The chain is sorted so that sectors increase, and so that
1937 * starting sectors increase.
1939 * After this it may still be that cfdisk doesnt like the table.
1940 * (This is because cfdisk considers expanded parts, from link to
1941 * end of partition, and these may still overlap.)
1943 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1947 fix_chain_of_logicals(void)
1949 int j, oj, ojj, sj, sjj;
1950 struct partition *pj,*pjj,tmp;
1952 /* Stage 1: sort sectors but leave sector of part 4 */
1953 /* (Its sector is the global extended_offset.) */
1955 for (j = 5; j < g_partitions - 1; j++) {
1956 oj = ptes[j].offset;
1957 ojj = ptes[j+1].offset;
1959 ptes[j].offset = ojj;
1960 ptes[j+1].offset = oj;
1961 pj = ptes[j].part_table;
1962 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1963 pjj = ptes[j+1].part_table;
1964 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1965 set_start_sect(ptes[j-1].ext_pointer,
1966 ojj-extended_offset);
1967 set_start_sect(ptes[j].ext_pointer,
1968 oj-extended_offset);
1973 /* Stage 2: sort starting sectors */
1975 for (j = 4; j < g_partitions - 1; j++) {
1976 pj = ptes[j].part_table;
1977 pjj = ptes[j+1].part_table;
1978 sj = get_start_sect(pj);
1979 sjj = get_start_sect(pjj);
1980 oj = ptes[j].offset;
1981 ojj = ptes[j+1].offset;
1982 if (oj+sj > ojj+sjj) {
1986 set_start_sect(pj, ojj+sjj-oj);
1987 set_start_sect(pjj, oj+sj-ojj);
1992 /* Probably something was changed */
1993 for (j = 4; j < g_partitions; j++)
1994 ptes[j].changed = 1;
1999 fix_partition_table_order(void)
2001 struct pte *pei, *pek;
2004 if (!wrong_p_order(NULL)) {
2005 printf("Ordering is already correct\n\n");
2009 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2010 /* partition i should have come earlier, move it */
2011 /* We have to move data in the MBR */
2012 struct partition *pi, *pk, *pe, pbuf;
2016 pe = pei->ext_pointer;
2017 pei->ext_pointer = pek->ext_pointer;
2018 pek->ext_pointer = pe;
2020 pi = pei->part_table;
2021 pk = pek->part_table;
2023 memmove(&pbuf, pi, sizeof(struct partition));
2024 memmove(pi, pk, sizeof(struct partition));
2025 memmove(pk, &pbuf, sizeof(struct partition));
2027 pei->changed = pek->changed = 1;
2031 fix_chain_of_logicals();
2039 list_table(int xtra)
2041 const struct partition *p;
2045 sun_list_table(xtra);
2049 sgi_list_table(xtra);
2053 list_disk_geometry();
2056 xbsd_print_disklabel(xtra);
2060 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2061 but if the device name ends in a digit, say /dev/foo1,
2062 then the partition is called /dev/foo1p3. */
2063 w = strlen(disk_device);
2064 if (w && isdigit(disk_device[w-1]))
2069 // 1 12345678901 12345678901 12345678901 12
2070 printf("%*s Boot Start End Blocks Id System\n",
2073 for (i = 0; i < g_partitions; i++) {
2074 const struct pte *pe = &ptes[i];
2080 if (!p || is_cleared_partition(p))
2083 psects = get_nr_sects(p);
2087 if (sector_size < 1024) {
2088 pblocks /= (1024 / sector_size);
2089 podd = psects % (1024 / sector_size);
2091 if (sector_size > 1024)
2092 pblocks *= (sector_size / 1024);
2094 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
2095 partname(disk_device, i+1, w+2),
2096 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2098 cround(get_partition_start(pe)), /* start */
2099 cround(get_partition_start(pe) + psects /* end */
2100 - (psects ? 1 : 0)),
2101 pblocks, podd ? '+' : ' ', /* odd flag on end */
2102 p->sys_ind, /* type id */
2103 partition_type(p->sys_ind)); /* type name */
2105 check_consistency(p, i);
2108 /* Is partition table in disk order? It need not be, but... */
2109 /* partition table entries are not checked for correct order
2110 * if this is a sgi, sun or aix labeled disk... */
2111 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2113 printf("\nPartition table entries are not in disk order\n");
2117 #if ENABLE_FEATURE_FDISK_ADVANCED
2119 x_list_table(int extend)
2121 const struct pte *pe;
2122 const struct partition *p;
2125 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2126 disk_device, g_heads, g_sectors, g_cylinders);
2127 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2128 for (i = 0; i < g_partitions; i++) {
2130 p = (extend ? pe->ext_pointer : pe->part_table);
2132 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2133 i + 1, p->boot_ind, p->head,
2135 cylinder(p->sector, p->cyl), p->end_head,
2136 sector(p->end_sector),
2137 cylinder(p->end_sector, p->end_cyl),
2138 get_start_sect(p), get_nr_sects(p),
2141 check_consistency(p, i);
2147 #if ENABLE_FEATURE_FDISK_WRITABLE
2149 fill_bounds(sector_t *first, sector_t *last)
2152 const struct pte *pe = &ptes[0];
2153 const struct partition *p;
2155 for (i = 0; i < g_partitions; pe++,i++) {
2157 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2158 first[i] = 0xffffffff;
2161 first[i] = get_partition_start(pe);
2162 last[i] = first[i] + get_nr_sects(p) - 1;
2168 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2170 sector_t total, real_s, real_c;
2172 real_s = sector(s) - 1;
2173 real_c = cylinder(s, c);
2174 total = (real_c * g_sectors + real_s) * g_heads + h;
2176 printf("Partition %u contains sector 0\n", n);
2178 printf("Partition %u: head %u greater than maximum %u\n",
2180 if (real_s >= g_sectors)
2181 printf("Partition %u: sector %u greater than "
2182 "maximum %u\n", n, s, g_sectors);
2183 if (real_c >= g_cylinders)
2184 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2185 "maximum %u\n", n, real_c + 1, g_cylinders);
2186 if (g_cylinders <= 1024 && start != total)
2187 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2188 "total %"SECT_FMT"u\n", n, start, total);
2196 sector_t first[g_partitions], last[g_partitions];
2197 struct partition *p;
2199 if (warn_geometry())
2211 fill_bounds(first, last);
2212 for (i = 0; i < g_partitions; i++) {
2213 struct pte *pe = &ptes[i];
2216 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2217 check_consistency(p, i);
2218 if (get_partition_start(pe) < first[i])
2219 printf("Warning: bad start-of-data in "
2220 "partition %u\n", i + 1);
2221 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2223 total += last[i] + 1 - first[i];
2224 for (j = 0; j < i; j++) {
2225 if ((first[i] >= first[j] && first[i] <= last[j])
2226 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2227 printf("Warning: partition %u overlaps "
2228 "partition %u\n", j + 1, i + 1);
2229 total += first[i] >= first[j] ?
2230 first[i] : first[j];
2231 total -= last[i] <= last[j] ?
2238 if (extended_offset) {
2239 struct pte *pex = &ptes[ext_index];
2240 sector_t e_last = get_start_sect(pex->part_table) +
2241 get_nr_sects(pex->part_table) - 1;
2243 for (i = 4; i < g_partitions; i++) {
2245 p = ptes[i].part_table;
2247 if (i != 4 || i + 1 < g_partitions)
2248 printf("Warning: partition %u "
2249 "is empty\n", i + 1);
2250 } else if (first[i] < extended_offset || last[i] > e_last) {
2251 printf("Logical partition %u not entirely in "
2252 "partition %u\n", i + 1, ext_index + 1);
2257 if (total > g_heads * g_sectors * g_cylinders)
2258 printf("Total allocated sectors %u greater than the maximum "
2259 "%u\n", total, g_heads * g_sectors * g_cylinders);
2261 total = g_heads * g_sectors * g_cylinders - total;
2263 printf("%"SECT_FMT"u unallocated sectors\n", total);
2268 add_partition(int n, int sys)
2270 char mesg[256]; /* 48 does not suffice in Japanese */
2271 int i, num_read = 0;
2272 struct partition *p = ptes[n].part_table;
2273 struct partition *q = ptes[ext_index].part_table;
2274 sector_t limit, temp;
2275 sector_t start, stop = 0;
2276 sector_t first[g_partitions], last[g_partitions];
2278 if (p && p->sys_ind) {
2279 printf(msg_part_already_defined, n + 1);
2282 fill_bounds(first, last);
2284 start = sector_offset;
2285 if (display_in_cyl_units || !total_number_of_sectors)
2286 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2288 limit = total_number_of_sectors - 1;
2289 if (extended_offset) {
2290 first[ext_index] = extended_offset;
2291 last[ext_index] = get_start_sect(q) +
2292 get_nr_sects(q) - 1;
2295 start = extended_offset + sector_offset;
2296 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2298 if (display_in_cyl_units)
2299 for (i = 0; i < g_partitions; i++)
2300 first[i] = (cround(first[i]) - 1) * units_per_sector;
2302 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2305 for (i = 0; i < g_partitions; i++) {
2308 if (start == ptes[i].offset)
2309 start += sector_offset;
2310 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2311 if (start >= first[i] && start <= lastplusoff)
2312 start = lastplusoff + 1;
2316 if (start >= temp+units_per_sector && num_read) {
2317 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2321 if (!num_read && start == temp) {
2322 sector_t saved_start;
2324 saved_start = start;
2325 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2327 if (display_in_cyl_units) {
2328 start = (start - 1) * units_per_sector;
2329 if (start < saved_start)
2330 start = saved_start;
2334 } while (start != temp || !num_read);
2335 if (n > 4) { /* NOT for fifth partition */
2336 struct pte *pe = &ptes[n];
2338 pe->offset = start - sector_offset;
2339 if (pe->offset == extended_offset) { /* must be corrected */
2341 if (sector_offset == 1)
2346 for (i = 0; i < g_partitions; i++) {
2347 struct pte *pe = &ptes[i];
2349 if (start < pe->offset && limit >= pe->offset)
2350 limit = pe->offset - 1;
2351 if (start < first[i] && limit >= first[i])
2352 limit = first[i] - 1;
2354 if (start > limit) {
2355 printf("No free sectors available\n");
2360 if (cround(start) == cround(limit)) {
2363 snprintf(mesg, sizeof(mesg),
2364 "Last %s or +size or +sizeM or +sizeK",
2365 str_units(SINGULAR));
2366 stop = read_int(cround(start), cround(limit), cround(limit),
2367 cround(start), mesg);
2368 if (display_in_cyl_units) {
2369 stop = stop * units_per_sector - 1;
2375 set_partition(n, 0, start, stop, sys);
2377 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2379 if (IS_EXTENDED(sys)) {
2380 struct pte *pe4 = &ptes[4];
2381 struct pte *pen = &ptes[n];
2384 pen->ext_pointer = p;
2385 pe4->offset = extended_offset = start;
2386 pe4->sectorbuffer = xzalloc(sector_size);
2387 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2388 pe4->ext_pointer = pe4->part_table + 1;
2397 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2398 struct pte *pe = &ptes[g_partitions];
2400 pe->sectorbuffer = xzalloc(sector_size);
2401 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2402 pe->ext_pointer = pe->part_table + 1;
2407 add_partition(g_partitions - 1, LINUX_NATIVE);
2413 int i, free_primary = 0;
2415 if (warn_geometry())
2419 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2423 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2427 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2428 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2429 "table first (use 'o'). This will destroy the present disk contents.\n");
2433 for (i = 0; i < 4; i++)
2434 free_primary += !ptes[i].part_table->sys_ind;
2436 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2437 printf("The maximum number of partitions has been created\n");
2441 if (!free_primary) {
2442 if (extended_offset)
2445 printf("You must delete some partition and add "
2446 "an extended partition first\n");
2449 snprintf(line, sizeof(line),
2452 " p primary partition (1-4)\n",
2454 "l logical (5 or over)" : "e extended"));
2456 c = read_nonempty(line);
2457 if (c == 'p' || c == 'P') {
2458 i = get_nonexisting_partition(0, 4);
2460 add_partition(i, LINUX_NATIVE);
2463 if (c == 'l' && extended_offset) {
2467 if (c == 'e' && !extended_offset) {
2468 i = get_nonexisting_partition(0, 4);
2470 add_partition(i, EXTENDED);
2473 printf("Invalid partition number "
2474 "for type '%c'\n", c);
2485 for (i = 0; i < 3; i++)
2486 if (ptes[i].changed)
2487 ptes[3].changed = 1;
2488 for (i = 3; i < g_partitions; i++) {
2489 struct pte *pe = &ptes[i];
2492 write_part_table_flag(pe->sectorbuffer);
2493 write_sector(pe->offset, pe->sectorbuffer);
2497 else if (LABEL_IS_SGI) {
2498 /* no test on change? the printf below might be mistaken */
2501 else if (LABEL_IS_SUN) {
2504 for (i = 0; i < 8; i++)
2505 if (ptes[i].changed)
2511 printf("The partition table has been altered!\n\n");
2512 reread_partition_table(1);
2516 reread_partition_table(int leave)
2520 printf("Calling ioctl() to re-read partition table\n");
2522 /* sleep(2); Huh? */
2523 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2524 "WARNING: rereading partition table "
2525 "failed, kernel still uses old table");
2529 "\nWARNING: If you have created or modified any DOS 6.x\n"
2530 "partitions, please see the fdisk manual page for additional\n"
2535 if (ENABLE_FEATURE_CLEAN_UP)
2540 #endif /* FEATURE_FDISK_WRITABLE */
2542 #if ENABLE_FEATURE_FDISK_ADVANCED
2543 #define MAX_PER_LINE 16
2545 print_buffer(char *pbuffer)
2549 for (i = 0, l = 0; i < sector_size; i++, l++) {
2551 printf("0x%03X:", i);
2552 printf(" %02X", (unsigned char) pbuffer[i]);
2553 if (l == MAX_PER_LINE - 1) {
2568 printf("Device: %s\n", disk_device);
2569 if (LABEL_IS_SGI || LABEL_IS_SUN)
2570 print_buffer(MBRbuffer);
2572 for (i = 3; i < g_partitions; i++)
2573 print_buffer(ptes[i].sectorbuffer);
2578 move_begin(unsigned i)
2580 struct pte *pe = &ptes[i];
2581 struct partition *p = pe->part_table;
2582 sector_t new, first;
2584 if (warn_geometry())
2586 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2587 printf("Partition %u has no data area\n", i + 1);
2590 first = get_partition_start(pe);
2591 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2592 "New beginning of data") - pe->offset;
2594 if (new != get_nr_sects(p)) {
2595 first = get_nr_sects(p) + get_start_sect(p) - new;
2596 set_nr_sects(p, first);
2597 set_start_sect(p, new);
2609 c = tolower(read_nonempty("Expert command (m for help): "));
2617 move_begin(get_partition(0, g_partitions));
2620 user_cylinders = g_cylinders =
2621 read_int(1, g_cylinders, 1048576, 0,
2622 "Number of cylinders");
2624 sun_set_ncyl(g_cylinders);
2634 else if (LABEL_IS_SUN)
2636 else if (LABEL_IS_DOS)
2641 fix_partition_table_order();
2644 #if ENABLE_FEATURE_SGI_LABEL
2649 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2668 if (ENABLE_FEATURE_CLEAN_UP)
2675 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2676 "Number of sectors");
2677 if (dos_compatible_flag) {
2678 sector_offset = g_sectors;
2679 printf("Warning: setting sector offset for DOS "
2688 write_table(); /* does not return */
2692 sun_set_pcylcount();
2699 #endif /* ADVANCED mode */
2702 is_ide_cdrom_or_tape(const char *device)
2706 struct stat statbuf;
2709 /* No device was given explicitly, and we are trying some
2710 likely things. But opening /dev/hdc may produce errors like
2711 "hdc: tray open or drive not ready"
2712 if it happens to be a CD-ROM drive. It even happens that
2713 the process hangs on the attempt to read a music CD.
2714 So try to be careful. This only works since 2.1.73. */
2716 if (strncmp("/dev/hd", device, 7))
2719 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2720 procf = fopen_for_read(buf);
2721 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2722 is_ide = (!strncmp(buf, "cdrom", 5) ||
2723 !strncmp(buf, "tape", 4));
2725 /* Now when this proc file does not exist, skip the
2726 device when it is read-only. */
2727 if (stat(device, &statbuf) == 0)
2728 is_ide = ((statbuf.st_mode & 0222) == 0);
2737 open_list_and_close(const char *device, int user_specified)
2741 disk_device = device;
2742 if (setjmp(listingbuf))
2744 if (!user_specified)
2745 if (is_ide_cdrom_or_tape(device))
2748 /* Open disk_device, save file descriptor to dev_fd */
2750 gb = get_boot(TRY_ONLY);
2751 if (gb > 0) { /* I/O error */
2752 /* Ignore other errors, since we try IDE
2753 and SCSI hard disks which may not be
2754 installed on the system. */
2755 if (user_specified || errno == EACCES)
2756 bb_perror_msg("can't open '%s'", device);
2760 if (gb < 0) { /* no DOS signature */
2761 list_disk_geometry();
2764 #if ENABLE_FEATURE_OSF_LABEL
2765 if (bsd_trydev(device) < 0)
2767 printf("Disk %s doesn't contain a valid "
2768 "partition table\n", device);
2771 #if ENABLE_FEATURE_FDISK_WRITABLE
2772 if (!LABEL_IS_SUN && g_partitions > 4) {
2773 delete_partition(ext_index);
2781 /* for fdisk -l: try all things in /proc/partitions
2782 that look like a partition name (do not end in a digit) */
2784 list_devs_in_proc_partititons(void)
2787 char line[100], ptname[100], devname[120], *s;
2790 procpt = fopen_or_warn("/proc/partitions", "r");
2792 while (fgets(line, sizeof(line), procpt)) {
2793 if (sscanf(line, " %u %u %u %[^\n ]",
2794 &ma, &mi, &sz, ptname) != 4)
2796 for (s = ptname; *s; s++)
2798 /* note: excluding '0': e.g. mmcblk0 is not a partition name! */
2799 if (s[-1] >= '1' && s[-1] <= '9')
2801 sprintf(devname, "/dev/%s", ptname);
2802 open_list_and_close(devname, 0);
2804 #if ENABLE_FEATURE_CLEAN_UP
2809 #if ENABLE_FEATURE_FDISK_WRITABLE
2811 unknown_command(int c)
2813 printf("%c: unknown command\n", c);
2817 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2818 int fdisk_main(int argc UNUSED_PARAM, char **argv)
2823 * fdisk -l [-b sectorsize] [-u] device ...
2824 * fdisk -s [partition] ...
2825 * fdisk [-b sectorsize] [-u] device
2827 * Options -C, -H, -S set the geometry.
2831 close_dev_fd(); /* needed: fd 3 must not stay closed */
2833 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2834 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2835 §or_size, &user_cylinders, &user_heads, &user_sectors);
2837 if (opt & OPT_b) { // -b
2838 /* Ugly: this sector size is really per device,
2839 so cannot be combined with multiple disks,
2840 and the same goes for the C/H/S options.
2842 if (sector_size != 512 && sector_size != 1024
2843 && sector_size != 2048)
2846 user_set_sector_size = 1;
2848 if (user_heads <= 0 || user_heads >= 256)
2850 if (user_sectors <= 0 || user_sectors >= 64)
2853 display_in_cyl_units = 0; // -u
2855 #if ENABLE_FEATURE_FDISK_WRITABLE
2862 open_list_and_close(*argv, 1);
2865 /* we don't have device names, */
2866 /* use /proc/partitions instead */
2867 list_devs_in_proc_partititons();
2870 #if ENABLE_FEATURE_FDISK_WRITABLE
2874 #if ENABLE_FEATURE_FDISK_BLKSIZE
2881 for (j = 0; argv[j]; j++) {
2882 unsigned long long size;
2883 fd = xopen(argv[j], O_RDONLY);
2884 size = bb_BLKGETSIZE_sectors(fd) / 2;
2887 printf("%llu\n", size);
2889 printf("%s: %llu\n", argv[j], size);
2895 #if ENABLE_FEATURE_FDISK_WRITABLE
2896 if (!argv[0] || argv[1])
2899 disk_device = argv[0];
2900 get_boot(OPEN_MAIN);
2903 /* OSF label, and no DOS label */
2904 printf("Detected an OSF/1 disklabel on %s, entering "
2905 "disklabel mode\n", disk_device);
2907 /*Why do we do this? It seems to be counter-intuitive*/
2908 current_label_type = LABEL_DOS;
2909 /* If we return we may want to make an empty DOS label? */
2915 c = tolower(read_nonempty("Command (m for help): "));
2919 toggle_active(get_partition(1, g_partitions));
2920 else if (LABEL_IS_SUN)
2921 toggle_sunflags(get_partition(1, g_partitions),
2923 else if (LABEL_IS_SGI)
2924 sgi_set_bootpartition(
2925 get_partition(1, g_partitions));
2931 printf("\nThe current boot file is: %s\n",
2932 sgi_get_bootfile());
2933 if (read_maybe_empty("Please enter the name of the "
2934 "new boot file: ") == '\n')
2935 printf("Boot file unchanged\n");
2937 sgi_set_bootfile(line_ptr);
2939 #if ENABLE_FEATURE_OSF_LABEL
2946 toggle_dos_compatibility_flag();
2947 else if (LABEL_IS_SUN)
2948 toggle_sunflags(get_partition(1, g_partitions),
2950 else if (LABEL_IS_SGI)
2951 sgi_set_swappartition(
2952 get_partition(1, g_partitions));
2959 /* If sgi_label then don't use get_existing_partition,
2960 let the user select a partition, since
2961 get_existing_partition() only works for Linux-like
2963 if (!LABEL_IS_SGI) {
2964 j = get_existing_partition(1, g_partitions);
2966 j = get_partition(1, g_partitions);
2969 delete_partition(j);
2978 list_types(get_sys_types());
2993 if (ENABLE_FEATURE_CLEAN_UP)
2998 #if ENABLE_FEATURE_SUN_LABEL
3012 write_table(); /* does not return */
3014 #if ENABLE_FEATURE_FDISK_ADVANCED
3017 printf("\n\tSorry, no experts menu for SGI "
3018 "partition tables available\n\n");
3029 #endif /* FEATURE_FDISK_WRITABLE */