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 GPLv2 or later, see file LICENSE in this source tree.
10 //config: bool "fdisk"
12 //config: select PLATFORM_LINUX
14 //config: The fdisk utility is used to divide hard disks into one or more
15 //config: logical disks, which are generally called partitions. This utility
16 //config: can be used to list and edit the set of partitions or BSD style
17 //config: 'disk slices' that are defined on a hard drive.
19 //config:config FDISK_SUPPORT_LARGE_DISKS
20 //config: bool "Support over 4GB disks"
22 //config: depends on FDISK
23 //config: depends on !LFS # with LFS no special code is needed
25 //config:config FEATURE_FDISK_WRITABLE
26 //config: bool "Write support"
28 //config: depends on FDISK
30 //config: Enabling this option allows you to create or change a partition table
31 //config: and write those changes out to disk. If you leave this option
32 //config: disabled, you will only be able to view the partition table.
34 //config:config FEATURE_AIX_LABEL
35 //config: bool "Support AIX disklabels"
37 //config: depends on FDISK && FEATURE_FDISK_WRITABLE
39 //config: Enabling this option allows you to create or change AIX disklabels.
40 //config: Most people can safely leave this option disabled.
42 //config:config FEATURE_SGI_LABEL
43 //config: bool "Support SGI disklabels"
45 //config: depends on FDISK && FEATURE_FDISK_WRITABLE
47 //config: Enabling this option allows you to create or change SGI disklabels.
48 //config: Most people can safely leave this option disabled.
50 //config:config FEATURE_SUN_LABEL
51 //config: bool "Support SUN disklabels"
53 //config: depends on FDISK && FEATURE_FDISK_WRITABLE
55 //config: Enabling this option allows you to create or change SUN disklabels.
56 //config: Most people can safely leave this option disabled.
58 //config:config FEATURE_OSF_LABEL
59 //config: bool "Support BSD disklabels"
61 //config: depends on FDISK && FEATURE_FDISK_WRITABLE
63 //config: Enabling this option allows you to create or change BSD disklabels
64 //config: and define and edit BSD disk slices.
66 //config:config FEATURE_GPT_LABEL
67 //config: bool "Support GPT disklabels"
69 //config: depends on FDISK && FEATURE_FDISK_WRITABLE
71 //config: Enabling this option allows you to view GUID Partition Table
74 //config:config FEATURE_FDISK_ADVANCED
75 //config: bool "Support expert mode"
77 //config: depends on FDISK && FEATURE_FDISK_WRITABLE
79 //config: Enabling this option allows you to do terribly unsafe things like
80 //config: define arbitrary drive geometry, move the beginning of data in a
81 //config: partition, and similarly evil things. Unless you have a very good
82 //config: reason you would be wise to leave this disabled.
84 //applet:IF_FDISK(APPLET(fdisk, BB_DIR_SBIN, BB_SUID_DROP))
86 //kbuild:lib-$(CONFIG_FDISK) += fdisk.o
88 /* Looks like someone forgot to add this to config system */
89 //usage:#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
90 //usage:# define ENABLE_FEATURE_FDISK_BLKSIZE 0
91 //usage:# define IF_FEATURE_FDISK_BLKSIZE(a)
94 //usage:#define fdisk_trivial_usage
95 //usage: "[-ul" IF_FEATURE_FDISK_BLKSIZE("s") "] "
96 //usage: "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK"
97 //usage:#define fdisk_full_usage "\n\n"
98 //usage: "Change partition table\n"
99 //usage: "\n -u Start and End are in sectors (instead of cylinders)"
100 //usage: "\n -l Show partition table for each DISK, then exit"
101 //usage: IF_FEATURE_FDISK_BLKSIZE(
102 //usage: "\n -s Show partition sizes in kb for each DISK, then exit"
104 //usage: "\n -b 2048 (for certain MO disks) use 2048-byte sectors"
105 //usage: "\n -C CYLINDERS Set number of cylinders/heads/sectors"
106 //usage: "\n -H HEADS Typically 255"
107 //usage: "\n -S SECTORS Typically 63"
109 #ifndef _LARGEFILE64_SOURCE
111 # define _LARGEFILE64_SOURCE
113 #include <assert.h> /* assert */
114 #include <sys/mount.h>
115 #if !defined(BLKSSZGET)
116 # define BLKSSZGET _IO(0x12, 104)
118 #if !defined(BLKGETSIZE64)
119 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
125 # define inline_if_little_endian ALWAYS_INLINE
127 # define inline_if_little_endian /* nothing */
131 /* Looks like someone forgot to add this to config system */
132 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
133 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
134 # define IF_FEATURE_FDISK_BLKSIZE(a)
137 #define DEFAULT_SECTOR_SIZE 512
138 #define DEFAULT_SECTOR_SIZE_STR "512"
139 #define MAX_SECTOR_SIZE 2048
140 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
141 #define MAXIMUM_PARTS 60
143 #define ACTIVE_FLAG 0x80
145 #define EXTENDED 0x05
146 #define WIN98_EXTENDED 0x0f
147 #define LINUX_PARTITION 0x81
148 #define LINUX_SWAP 0x82
149 #define LINUX_NATIVE 0x83
150 #define LINUX_EXTENDED 0x85
151 #define LINUX_LVM 0x8e
152 #define LINUX_RAID 0xfd
162 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
166 typedef unsigned long long ullong;
167 /* Used for sector numbers. Partition formats we know
168 * do not support more than 2^32 sectors
170 typedef uint32_t sector_t;
171 #if UINT_MAX == 4294967295
173 #elif ULONG_MAX == 4294967295
174 # define SECT_FMT "l"
176 # error Cant detect sizeof(uint32_t)
181 unsigned char sectors;
182 unsigned short cylinders;
186 #define HDIO_GETGEO 0x0301 /* get device geometry */
188 static const char msg_building_new_label[] ALIGN1 =
189 "Building a new %s. Changes will remain in memory only,\n"
190 "until you decide to write them. After that the previous content\n"
191 "won't be recoverable.\n\n";
193 static const char msg_part_already_defined[] ALIGN1 =
194 "Partition %u is already defined, delete it before re-adding\n";
198 unsigned char boot_ind; /* 0x80 - active */
199 unsigned char head; /* starting head */
200 unsigned char sector; /* starting sector */
201 unsigned char cyl; /* starting cylinder */
202 unsigned char sys_ind; /* what partition type */
203 unsigned char end_head; /* end head */
204 unsigned char end_sector; /* end sector */
205 unsigned char end_cyl; /* end cylinder */
206 unsigned char start4[4]; /* starting sector counting from 0 */
207 unsigned char size4[4]; /* nr of sectors in partition */
211 * per partition table entry data
213 * The four primary partitions have the same sectorbuffer (MBRbuffer)
214 * and have NULL ext_pointer.
215 * Each logical partition table entry has two pointers, one for the
216 * partition and one link to the next one.
219 struct partition *part_table; /* points into sectorbuffer */
220 struct partition *ext_pointer; /* points into sectorbuffer */
221 sector_t offset_from_dev_start; /* disk sector number */
222 char *sectorbuffer; /* disk sector contents */
223 #if ENABLE_FEATURE_FDISK_WRITABLE
224 char changed; /* boolean */
228 #define unable_to_open "can't open '%s'"
229 #define unable_to_read "can't read from %s"
230 #define unable_to_seek "can't seek on %s"
233 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT
236 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
238 #if ENABLE_FEATURE_SUN_LABEL
239 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
240 #define STATIC_SUN static
242 #define LABEL_IS_SUN 0
243 #define STATIC_SUN extern
246 #if ENABLE_FEATURE_SGI_LABEL
247 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
248 #define STATIC_SGI static
250 #define LABEL_IS_SGI 0
251 #define STATIC_SGI extern
254 #if ENABLE_FEATURE_AIX_LABEL
255 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
256 #define STATIC_AIX static
258 #define LABEL_IS_AIX 0
259 #define STATIC_AIX extern
262 #if ENABLE_FEATURE_OSF_LABEL
263 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
264 #define STATIC_OSF static
266 #define LABEL_IS_OSF 0
267 #define STATIC_OSF extern
270 #if ENABLE_FEATURE_GPT_LABEL
271 #define LABEL_IS_GPT (LABEL_GPT == current_label_type)
272 #define STATIC_GPT static
274 #define LABEL_IS_GPT 0
275 #define STATIC_GPT extern
278 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
280 static void update_units(void);
281 #if ENABLE_FEATURE_FDISK_WRITABLE
282 static void change_units(void);
283 static void reread_partition_table(int leave);
284 static void delete_partition(int i);
285 static unsigned get_partition(int warn, unsigned max);
286 static void list_types(const char *const *sys);
287 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
289 static const char *partition_type(unsigned char type);
290 static void get_geometry(void);
291 static void read_pte(struct pte *pe, sector_t offset);
292 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
293 static int get_boot(enum action what);
295 static int get_boot(void);
301 static sector_t get_start_sect(const struct partition *p);
302 static sector_t get_nr_sects(const struct partition *p);
304 /* DOS partition types */
306 static const char *const i386_sys_types[] = {
310 "\x05" "Extended", /* DOS 3.3+ extended partition */
311 "\x06" "FAT16", /* DOS 16-bit >=32M */
312 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
313 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
314 "\x0b" "Win95 FAT32",
315 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
316 "\x0e" "Win95 FAT16 (LBA)",
317 "\x0f" "Win95 Ext'd (LBA)",
318 "\x11" "Hidden FAT12",
319 "\x12" "Compaq diagnostics",
320 "\x14" "Hidden FAT16 <32M",
321 "\x16" "Hidden FAT16",
322 "\x17" "Hidden HPFS/NTFS",
323 "\x1b" "Hidden Win95 FAT32",
324 "\x1c" "Hidden W95 FAT32 (LBA)",
325 "\x1e" "Hidden W95 FAT16 (LBA)",
326 "\x3c" "Part.Magic recovery",
327 "\x41" "PPC PReP Boot",
329 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
330 "\x80" "Old Minix", /* Minix 1.4a and earlier */
331 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
332 "\x82" "Linux swap", /* also Solaris */
334 "\x84" "OS/2 hidden C: drive",
335 "\x85" "Linux extended",
336 "\x86" "NTFS volume set",
337 "\x87" "NTFS volume set",
339 "\x9f" "BSD/OS", /* BSDI */
340 "\xa0" "Thinkpad hibernation",
341 "\xa5" "FreeBSD", /* various BSD flavours */
345 "\xab" "Darwin boot",
348 "\xbe" "Solaris boot",
350 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
351 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
352 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
353 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
354 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
355 autodetect using persistent
357 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
360 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
361 "\x09" "AIX bootable", /* AIX data or Coherent */
363 "\x18" "AST SmartSleep",
366 "\x40" "Venix 80286",
368 "\x4e" "QNX4.x 2nd part",
369 "\x4f" "QNX4.x 3rd part",
371 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
372 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
373 "\x53" "OnTrack DM6 Aux3",
377 "\x5c" "Priam Edisk",
379 "\x64" "Novell Netware 286",
380 "\x65" "Novell Netware 386",
381 "\x70" "DiskSecure Multi-Boot",
384 "\x94" "Amoeba BBT", /* (bad block table) */
386 "\xbb" "Boot Wizard hidden",
387 "\xc1" "DRDOS/sec (FAT-12)",
388 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
389 "\xc6" "DRDOS/sec (FAT-16)",
391 "\xda" "Non-FS data",
392 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
393 Concurrent DOS or CTOS */
394 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
395 "\xdf" "BootIt", /* BootIt EMBRM */
396 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
397 extended partition */
398 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
399 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
400 partition < 1024 cyl. */
402 "\xf4" "SpeedStor", /* SpeedStor large partition */
403 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
404 "\xff" "BBT", /* Xenix Bad Block Table */
410 dev_fd = 3 /* the disk */
417 const char *disk_device;
418 int g_partitions; // = 4; /* maximum partition + 1 */
419 unsigned units_per_sector; // = 1;
420 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
421 unsigned user_set_sector_size;
422 unsigned sector_offset; // = 1;
423 unsigned g_heads, g_sectors, g_cylinders;
424 smallint /* enum label_type */ current_label_type;
425 smallint display_in_cyl_units; // = 1;
426 #if ENABLE_FEATURE_OSF_LABEL
427 smallint possibly_osf_label;
430 smallint listing; /* no aborts for fdisk -l */
431 smallint dos_compatible_flag; // = 1;
432 #if ENABLE_FEATURE_FDISK_WRITABLE
434 smallint nowarn; /* no warnings for fdisk -l/-s */
436 int ext_index; /* the prime extended partition */
437 unsigned user_cylinders, user_heads, user_sectors;
438 unsigned pt_heads, pt_sectors;
439 unsigned kern_heads, kern_sectors;
440 sector_t extended_offset; /* offset of link pointers */
441 sector_t total_number_of_sectors;
444 char line_buffer[80];
445 /* Raw disk label. For DOS-type partition tables the MBR,
446 * with descriptions of the primary partitions. */
447 char MBRbuffer[MAX_SECTOR_SIZE];
448 /* Partition tables */
449 struct pte ptes[MAXIMUM_PARTS];
451 #define G (*ptr_to_globals)
452 #define line_ptr (G.line_ptr )
453 #define disk_device (G.disk_device )
454 #define g_partitions (G.g_partitions )
455 #define units_per_sector (G.units_per_sector )
456 #define sector_size (G.sector_size )
457 #define user_set_sector_size (G.user_set_sector_size)
458 #define sector_offset (G.sector_offset )
459 #define g_heads (G.g_heads )
460 #define g_sectors (G.g_sectors )
461 #define g_cylinders (G.g_cylinders )
462 #define current_label_type (G.current_label_type )
463 #define display_in_cyl_units (G.display_in_cyl_units)
464 #define possibly_osf_label (G.possibly_osf_label )
465 #define listing (G.listing )
466 #define dos_compatible_flag (G.dos_compatible_flag )
467 #define nowarn (G.nowarn )
468 #define ext_index (G.ext_index )
469 #define user_cylinders (G.user_cylinders )
470 #define user_heads (G.user_heads )
471 #define user_sectors (G.user_sectors )
472 #define pt_heads (G.pt_heads )
473 #define pt_sectors (G.pt_sectors )
474 #define kern_heads (G.kern_heads )
475 #define kern_sectors (G.kern_sectors )
476 #define extended_offset (G.extended_offset )
477 #define total_number_of_sectors (G.total_number_of_sectors)
478 #define listingbuf (G.listingbuf )
479 #define line_buffer (G.line_buffer )
480 #define MBRbuffer (G.MBRbuffer )
481 #define ptes (G.ptes )
482 #define INIT_G() do { \
483 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
484 sector_size = DEFAULT_SECTOR_SIZE; \
487 display_in_cyl_units = 1; \
488 units_per_sector = 1; \
489 dos_compatible_flag = 1; \
493 /* TODO: move to libbb? */
494 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
495 * disks > 2^32 sectors
497 static sector_t bb_BLKGETSIZE_sectors(int fd)
500 unsigned long longsectors;
502 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
503 /* Got bytes, convert to 512 byte sectors */
505 if (v64 != (sector_t)v64) {
507 /* Not only DOS, but all other partition tables
508 * we support can't record more than 32 bit
509 * sector counts or offsets
511 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
516 /* Needs temp of type long */
517 if (ioctl(fd, BLKGETSIZE, &longsectors)) {
518 /* Perhaps this is a disk image */
519 off_t sz = lseek(fd, 0, SEEK_END);
522 longsectors = (uoff_t)sz / sector_size;
523 lseek(fd, 0, SEEK_SET);
525 if (sizeof(long) > sizeof(sector_t)
526 && longsectors != (sector_t)longsectors
534 #define IS_EXTENDED(i) \
535 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
537 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
539 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
541 #define pt_offset(b, n) \
542 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
544 #define sector(s) ((s) & 0x3f)
546 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
551 /* Not really closing, but making sure it is open, and to harmless place */
552 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
555 /* Return partition name */
557 partname(const char *dev, int pno, int lth)
564 bufp = auto_string(xzalloc(80));
570 if (isdigit(dev[w-1]))
573 /* devfs kludge - note: fdisk partition names are not supposed
574 to equal kernel names, so there is no reason to do this */
575 if (strcmp(dev + w - 4, "disc") == 0) {
583 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
584 lth-wp-2, w, dev, p, pno);
586 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
591 static ALWAYS_INLINE struct partition *
592 get_part_table(int i)
594 return ptes[i].part_table;
599 { /* n==1: use singular */
601 return display_in_cyl_units ? "cylinder" : "sector";
602 return display_in_cyl_units ? "cylinders" : "sectors";
606 valid_part_table_flag(const char *mbuffer)
608 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
611 static void fdisk_fatal(const char *why)
615 longjmp(listingbuf, 1);
617 bb_error_msg_and_die(why, disk_device);
621 seek_sector(sector_t secno)
623 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
624 off64_t off = (off64_t)secno * sector_size;
625 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
626 fdisk_fatal(unable_to_seek);
628 uint64_t off = (uint64_t)secno * sector_size;
629 if (off > MAXINT(off_t)
630 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
632 fdisk_fatal(unable_to_seek);
637 #if ENABLE_FEATURE_FDISK_WRITABLE
638 /* Read line; return 0 or first printable char */
640 read_line(const char *prompt)
644 sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
646 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
648 if (line_buffer[sz-1] == '\n')
649 line_buffer[--sz] = '\0';
651 line_ptr = line_buffer;
652 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
658 set_all_unchanged(void)
662 for (i = 0; i < MAXIMUM_PARTS; i++)
666 static ALWAYS_INLINE void
672 static ALWAYS_INLINE void
673 write_part_table_flag(char *b)
680 read_nonempty(const char *mesg)
682 while (!read_line(mesg))
688 read_maybe_empty(const char *mesg)
690 if (!read_line(mesg)) {
691 line_ptr = line_buffer;
699 read_hex(const char *const *sys)
703 read_nonempty("Hex code (type L to list codes): ");
704 if ((line_ptr[0] | 0x20) == 'l') {
708 v = bb_strtoul(line_ptr, NULL, 16);
715 write_sector(sector_t secno, const void *buf)
718 xwrite(dev_fd, buf, sector_size);
720 #endif /* FEATURE_FDISK_WRITABLE */
723 #include "fdisk_aix.c"
725 struct sun_partition {
726 unsigned char info[128]; /* Informative text string */
727 unsigned char spare0[14];
729 unsigned char spare1;
731 unsigned char spare2;
734 unsigned char spare1[246]; /* Boot information etc. */
735 unsigned short rspeed; /* Disk rotational speed */
736 unsigned short pcylcount; /* Physical cylinder count */
737 unsigned short sparecyl; /* extra sects per cylinder */
738 unsigned char spare2[4]; /* More magic... */
739 unsigned short ilfact; /* Interleave factor */
740 unsigned short ncyl; /* Data cylinder count */
741 unsigned short nacyl; /* Alt. cylinder count */
742 unsigned short ntrks; /* Tracks per cylinder */
743 unsigned short nsect; /* Sectors per track */
744 unsigned char spare3[4]; /* Even more magic... */
745 struct sun_partinfo {
746 uint32_t start_cylinder;
747 uint32_t num_sectors;
749 unsigned short magic; /* Magic number */
750 unsigned short csum; /* Label xor'd checksum */
752 typedef struct sun_partition sun_partition;
753 #define sunlabel ((sun_partition *)MBRbuffer)
754 STATIC_OSF void bsd_select(void);
755 STATIC_OSF void xbsd_print_disklabel(int);
756 #include "fdisk_osf.c"
758 STATIC_GPT void gpt_list_table(int xtra);
759 #include "fdisk_gpt.c"
761 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
763 fdisk_swap16(uint16_t x)
765 return (x << 8) | (x >> 8);
769 fdisk_swap32(uint32_t x)
772 ((x & 0xFF00) << 8) |
773 ((x & 0xFF0000) >> 8) |
778 STATIC_SGI const char *const sgi_sys_types[];
779 STATIC_SGI unsigned sgi_get_num_sectors(int i);
780 STATIC_SGI int sgi_get_sysid(int i);
781 STATIC_SGI void sgi_delete_partition(int i);
782 STATIC_SGI void sgi_change_sysid(int i, int sys);
783 STATIC_SGI void sgi_list_table(int xtra);
784 #if ENABLE_FEATURE_FDISK_ADVANCED
785 STATIC_SGI void sgi_set_xcyl(void);
787 STATIC_SGI int verify_sgi(int verbose);
788 STATIC_SGI void sgi_add_partition(int n, int sys);
789 STATIC_SGI void sgi_set_swappartition(int i);
790 STATIC_SGI const char *sgi_get_bootfile(void);
791 STATIC_SGI void sgi_set_bootfile(const char* aFile);
792 STATIC_SGI void create_sgiinfo(void);
793 STATIC_SGI void sgi_write_table(void);
794 STATIC_SGI void sgi_set_bootpartition(int i);
795 #include "fdisk_sgi.c"
797 STATIC_SUN const char *const sun_sys_types[];
798 STATIC_SUN void sun_delete_partition(int i);
799 STATIC_SUN void sun_change_sysid(int i, int sys);
800 STATIC_SUN void sun_list_table(int xtra);
801 STATIC_SUN void add_sun_partition(int n, int sys);
802 #if ENABLE_FEATURE_FDISK_ADVANCED
803 STATIC_SUN void sun_set_alt_cyl(void);
804 STATIC_SUN void sun_set_ncyl(int cyl);
805 STATIC_SUN void sun_set_xcyl(void);
806 STATIC_SUN void sun_set_ilfact(void);
807 STATIC_SUN void sun_set_rspeed(void);
808 STATIC_SUN void sun_set_pcylcount(void);
810 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
811 STATIC_SUN void verify_sun(void);
812 STATIC_SUN void sun_write_table(void);
813 #include "fdisk_sun.c"
816 static inline_if_little_endian unsigned
817 read4_little_endian(const unsigned char *cp)
820 move_from_unaligned32(v, cp);
825 get_start_sect(const struct partition *p)
827 return read4_little_endian(p->start4);
831 get_nr_sects(const struct partition *p)
833 return read4_little_endian(p->size4);
836 #if ENABLE_FEATURE_FDISK_WRITABLE
837 /* start_sect and nr_sects are stored little endian on all machines */
838 /* moreover, they are not aligned correctly */
839 static inline_if_little_endian void
840 store4_little_endian(unsigned char *cp, unsigned val)
842 uint32_t v = SWAP_LE32(val);
843 move_to_unaligned32(cp, v);
847 set_start_sect(struct partition *p, unsigned start_sect)
849 store4_little_endian(p->start4, start_sect);
853 set_nr_sects(struct partition *p, unsigned nr_sects)
855 store4_little_endian(p->size4, nr_sects);
859 /* Allocate a buffer and read a partition table sector */
861 read_pte(struct pte *pe, sector_t offset)
863 pe->offset_from_dev_start = offset;
864 pe->sectorbuffer = xzalloc(sector_size);
866 /* xread would make us abort - bad for fdisk -l */
867 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
868 fdisk_fatal(unable_to_read);
869 #if ENABLE_FEATURE_FDISK_WRITABLE
872 pe->part_table = pe->ext_pointer = NULL;
876 get_partition_start_from_dev_start(const struct pte *pe)
878 return pe->offset_from_dev_start + get_start_sect(pe->part_table);
881 #if ENABLE_FEATURE_FDISK_WRITABLE
883 * Avoid warning about DOS partitions when no DOS partition was changed.
884 * Here a heuristic "is probably dos partition".
885 * We might also do the opposite and warn in all cases except
886 * for "is probably nondos partition".
890 is_dos_partition(int t)
892 return (t == 1 || t == 4 || t == 6 ||
893 t == 0x0b || t == 0x0c || t == 0x0e ||
894 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
895 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
896 t == 0xc1 || t == 0xc4 || t == 0xc6);
903 puts("Command Action");
905 puts("a\ttoggle a read only flag"); /* sun */
906 puts("b\tedit bsd disklabel");
907 puts("c\ttoggle the mountable flag"); /* sun */
908 puts("d\tdelete a partition");
909 puts("l\tlist known partition types");
910 puts("n\tadd a new partition");
911 puts("o\tcreate a new empty DOS partition table");
912 puts("p\tprint the partition table");
913 puts("q\tquit without saving changes");
914 puts("s\tcreate a new empty Sun disklabel"); /* sun */
915 puts("t\tchange a partition's system id");
916 puts("u\tchange display/entry units");
917 puts("v\tverify the partition table");
918 puts("w\twrite table to disk and exit");
919 #if ENABLE_FEATURE_FDISK_ADVANCED
920 puts("x\textra functionality (experts only)");
922 } else if (LABEL_IS_SGI) {
923 puts("a\tselect bootable partition"); /* sgi flavour */
924 puts("b\tedit bootfile entry"); /* sgi */
925 puts("c\tselect sgi swap partition"); /* sgi flavour */
926 puts("d\tdelete a partition");
927 puts("l\tlist known partition types");
928 puts("n\tadd a new partition");
929 puts("o\tcreate a new empty DOS partition table");
930 puts("p\tprint the partition table");
931 puts("q\tquit without saving changes");
932 puts("s\tcreate a new empty Sun disklabel"); /* sun */
933 puts("t\tchange a partition's system id");
934 puts("u\tchange display/entry units");
935 puts("v\tverify the partition table");
936 puts("w\twrite table to disk and exit");
937 } else if (LABEL_IS_AIX) {
938 puts("o\tcreate a new empty DOS partition table");
939 puts("q\tquit without saving changes");
940 puts("s\tcreate a new empty Sun disklabel"); /* sun */
941 } else if (LABEL_IS_GPT) {
942 puts("o\tcreate a new empty DOS partition table");
943 puts("p\tprint the partition table");
944 puts("q\tquit without saving changes");
945 puts("s\tcreate a new empty Sun disklabel"); /* sun */
947 puts("a\ttoggle a bootable flag");
948 puts("b\tedit bsd disklabel");
949 puts("c\ttoggle the dos compatibility flag");
950 puts("d\tdelete a partition");
951 puts("l\tlist known partition types");
952 puts("n\tadd a new partition");
953 puts("o\tcreate a new empty DOS partition table");
954 puts("p\tprint the partition table");
955 puts("q\tquit without saving changes");
956 puts("s\tcreate a new empty Sun disklabel"); /* sun */
957 puts("t\tchange a partition's system id");
958 puts("u\tchange display/entry units");
959 puts("v\tverify the partition table");
960 puts("w\twrite table to disk and exit");
961 #if ENABLE_FEATURE_FDISK_ADVANCED
962 puts("x\textra functionality (experts only)");
966 #endif /* FEATURE_FDISK_WRITABLE */
969 #if ENABLE_FEATURE_FDISK_ADVANCED
973 puts("Command Action");
975 puts("a\tchange number of alternate cylinders"); /*sun*/
976 puts("c\tchange number of cylinders");
977 puts("d\tprint the raw data in the partition table");
978 puts("e\tchange number of extra sectors per cylinder");/*sun*/
979 puts("h\tchange number of heads");
980 puts("i\tchange interleave factor"); /*sun*/
981 puts("o\tchange rotation speed (rpm)"); /*sun*/
982 puts("p\tprint the partition table");
983 puts("q\tquit without saving changes");
984 puts("r\treturn to main menu");
985 puts("s\tchange number of sectors/track");
986 puts("v\tverify the partition table");
987 puts("w\twrite table to disk and exit");
988 puts("y\tchange number of physical cylinders"); /*sun*/
989 } else if (LABEL_IS_SGI) {
990 puts("b\tmove beginning of data in a partition"); /* !sun */
991 puts("c\tchange number of cylinders");
992 puts("d\tprint the raw data in the partition table");
993 puts("e\tlist extended partitions"); /* !sun */
994 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
995 puts("h\tchange number of heads");
996 puts("p\tprint the partition table");
997 puts("q\tquit without saving changes");
998 puts("r\treturn to main menu");
999 puts("s\tchange number of sectors/track");
1000 puts("v\tverify the partition table");
1001 puts("w\twrite table to disk and exit");
1002 } else if (LABEL_IS_AIX) {
1003 puts("b\tmove beginning of data in a partition"); /* !sun */
1004 puts("c\tchange number of cylinders");
1005 puts("d\tprint the raw data in the partition table");
1006 puts("e\tlist extended partitions"); /* !sun */
1007 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
1008 puts("h\tchange number of heads");
1009 puts("p\tprint the partition table");
1010 puts("q\tquit without saving changes");
1011 puts("r\treturn to main menu");
1012 puts("s\tchange number of sectors/track");
1013 puts("v\tverify the partition table");
1014 puts("w\twrite table to disk and exit");
1016 puts("b\tmove beginning of data in a partition"); /* !sun */
1017 puts("c\tchange number of cylinders");
1018 puts("d\tprint the raw data in the partition table");
1019 puts("e\tlist extended partitions"); /* !sun */
1020 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
1021 #if ENABLE_FEATURE_SGI_LABEL
1022 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
1024 puts("h\tchange number of heads");
1025 puts("p\tprint the partition table");
1026 puts("q\tquit without saving changes");
1027 puts("r\treturn to main menu");
1028 puts("s\tchange number of sectors/track");
1029 puts("v\tverify the partition table");
1030 puts("w\twrite table to disk and exit");
1033 #endif /* ADVANCED mode */
1035 #if ENABLE_FEATURE_FDISK_WRITABLE
1036 static const char *const *
1040 LABEL_IS_SUN ? sun_sys_types :
1041 LABEL_IS_SGI ? sgi_sys_types :
1045 #define get_sys_types() i386_sys_types
1049 partition_type(unsigned char type)
1052 const char *const *types = get_sys_types();
1054 for (i = 0; types[i]; i++)
1055 if ((unsigned char)types[i][0] == type)
1056 return types[i] + 1;
1062 is_cleared_partition(const struct partition *p)
1064 /* We consider partition "cleared" only if it has only zeros */
1065 const char *cp = (const char *)p;
1066 int cnt = sizeof(*p);
1074 clear_partition(struct partition *p)
1077 memset(p, 0, sizeof(*p));
1080 #if ENABLE_FEATURE_FDISK_WRITABLE
1084 return LABEL_IS_SUN ? sunlabel->infos[i].id :
1085 (LABEL_IS_SGI ? sgi_get_sysid(i) :
1086 ptes[i].part_table->sys_ind);
1090 list_types(const char *const *sys)
1094 unsigned last[COLS];
1095 unsigned done, next, size;
1098 for (size = 0; sys[size]; size++)
1102 for (i = COLS-1; i >= 0; i--) {
1103 done += (size + i - done) / (i + 1);
1104 last[COLS-1 - i] = done;
1107 i = done = next = 0;
1109 printf("%c%2x %-22.22s", i ? ' ' : '\n',
1110 (unsigned char)sys[next][0],
1112 next = last[i++] + done;
1113 if (i >= COLS || next >= last[i]) {
1117 } while (done < last[0]);
1121 #define set_hsc(h, s, c, sector) do \
1123 s = sector % g_sectors + 1; \
1124 sector /= g_sectors; \
1125 h = sector % g_heads; \
1126 sector /= g_heads; \
1127 c = sector & 0xff; \
1128 s |= (sector >> 2) & 0xc0; \
1131 static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop)
1133 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1134 start = g_heads * g_sectors * 1024 - 1;
1135 set_hsc(p->head, p->sector, p->cyl, start);
1137 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1138 stop = g_heads * g_sectors * 1024 - 1;
1139 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1143 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1145 struct partition *p;
1149 p = ptes[i].ext_pointer;
1150 offset = extended_offset;
1152 p = ptes[i].part_table;
1153 offset = ptes[i].offset_from_dev_start;
1157 set_start_sect(p, start - offset);
1158 set_nr_sects(p, stop - start + 1);
1159 set_hsc_start_end(p, start, stop);
1160 ptes[i].changed = 1;
1167 if (g_heads && g_sectors && g_cylinders)
1170 printf("Unknown value(s) for:");
1176 printf(" cylinders");
1177 #if ENABLE_FEATURE_FDISK_WRITABLE
1178 puts(" (settable in the extra functions menu)");
1188 int cyl_units = g_heads * g_sectors;
1190 if (display_in_cyl_units && cyl_units)
1191 units_per_sector = cyl_units;
1193 units_per_sector = 1; /* in sectors */
1196 #if ENABLE_FEATURE_FDISK_WRITABLE
1198 warn_cylinders(void)
1200 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1202 "The number of cylinders for this disk is set to %u.\n"
1203 "There is nothing wrong with that, but this is larger than 1024,\n"
1204 "and could in certain setups cause problems with:\n"
1205 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1206 "2) booting and partitioning software from other OSs\n"
1207 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1213 read_extended(int ext)
1217 struct partition *p, *q;
1221 pex->ext_pointer = pex->part_table;
1223 p = pex->part_table;
1224 if (!get_start_sect(p)) {
1225 puts("Bad offset in primary extended partition");
1229 while (IS_EXTENDED(p->sys_ind)) {
1230 struct pte *pe = &ptes[g_partitions];
1232 if (g_partitions >= MAXIMUM_PARTS) {
1233 /* This is not a Linux restriction, but
1234 this program uses arrays of size MAXIMUM_PARTS.
1235 Do not try to 'improve' this test. */
1236 struct pte *pre = &ptes[g_partitions - 1];
1237 #if ENABLE_FEATURE_FDISK_WRITABLE
1238 printf("Warning: deleting partitions after %u\n",
1242 clear_partition(pre->ext_pointer);
1246 read_pte(pe, extended_offset + get_start_sect(p));
1248 if (!extended_offset)
1249 extended_offset = get_start_sect(p);
1251 q = p = pt_offset(pe->sectorbuffer, 0);
1252 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1253 if (IS_EXTENDED(p->sys_ind)) {
1254 if (pe->ext_pointer)
1255 printf("Warning: extra link "
1256 "pointer in partition table"
1257 " %u\n", g_partitions + 1);
1259 pe->ext_pointer = p;
1260 } else if (p->sys_ind) {
1262 printf("Warning: ignoring extra "
1263 "data in partition table"
1264 " %u\n", g_partitions + 1);
1270 /* very strange code here... */
1271 if (!pe->part_table) {
1272 if (q != pe->ext_pointer)
1275 pe->part_table = q + 1;
1277 if (!pe->ext_pointer) {
1278 if (q != pe->part_table)
1279 pe->ext_pointer = q;
1281 pe->ext_pointer = q + 1;
1284 p = pe->ext_pointer;
1288 #if ENABLE_FEATURE_FDISK_WRITABLE
1289 /* remove empty links */
1291 for (i = 4; i < g_partitions; i++) {
1292 struct pte *pe = &ptes[i];
1294 if (!get_nr_sects(pe->part_table)
1295 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1297 printf("Omitting empty partition (%u)\n", i+1);
1298 delete_partition(i);
1299 goto remove; /* numbering changed */
1305 #if ENABLE_FEATURE_FDISK_WRITABLE
1307 create_doslabel(void)
1309 printf(msg_building_new_label, "DOS disklabel");
1311 current_label_type = LABEL_DOS;
1312 #if ENABLE_FEATURE_OSF_LABEL
1313 possibly_osf_label = 0;
1317 memset(&MBRbuffer[510 - 4*16], 0, 4*16);
1318 write_part_table_flag(MBRbuffer);
1319 extended_offset = 0;
1320 set_all_unchanged();
1322 get_boot(CREATE_EMPTY_DOS);
1327 get_sectorsize(void)
1329 if (!user_set_sector_size) {
1331 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1333 if (sector_size != DEFAULT_SECTOR_SIZE)
1334 printf("Note: sector size is %u "
1335 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1341 get_kernel_geometry(void)
1343 struct hd_geometry geometry;
1345 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1346 kern_heads = geometry.heads;
1347 kern_sectors = geometry.sectors;
1348 /* never use geometry.cylinders - it is truncated */
1353 get_partition_table_geometry(void)
1355 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1356 struct partition *p;
1357 int i, h, s, hh, ss;
1361 if (!(valid_part_table_flag((char*)bufp)))
1365 for (i = 0; i < 4; i++) {
1366 p = pt_offset(bufp, i);
1367 if (p->sys_ind != 0) {
1368 h = p->end_head + 1;
1369 s = (p->end_sector & 077);
1374 } else if (hh != h || ss != s)
1379 if (!first && !bad) {
1391 sec_fac = sector_size / 512;
1392 #if ENABLE_FEATURE_SUN_LABEL
1393 guess_device_type();
1395 g_heads = g_cylinders = g_sectors = 0;
1396 kern_heads = kern_sectors = 0;
1397 pt_heads = pt_sectors = 0;
1399 get_kernel_geometry();
1400 get_partition_table_geometry();
1402 g_heads = user_heads ? user_heads :
1403 pt_heads ? pt_heads :
1404 kern_heads ? kern_heads : 255;
1405 g_sectors = user_sectors ? user_sectors :
1406 pt_sectors ? pt_sectors :
1407 kern_sectors ? kern_sectors : 63;
1408 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1411 if (dos_compatible_flag)
1412 sector_offset = g_sectors;
1414 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1416 g_cylinders = user_cylinders;
1420 * Opens disk_device and optionally reads MBR.
1421 * If what == OPEN_MAIN:
1422 * Open device, read MBR. Abort program on short read. Create empty
1423 * disklabel if the on-disk structure is invalid (WRITABLE mode).
1424 * If what == TRY_ONLY:
1425 * Open device, read MBR. Return an error if anything is out of place.
1426 * Do not create an empty disklabel. This is used for the "list"
1427 * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
1428 * If what == CREATE_EMPTY_*:
1429 * This means that get_boot() was called recursively from create_*label().
1430 * Do not re-open the device; just set up the ptes array and print
1431 * geometry warnings.
1434 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1435 * 0: found or created label
1438 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1439 static int get_boot(enum action what)
1441 static int get_boot(void)
1442 #define get_boot(what) get_boot()
1448 for (i = 0; i < 4; i++) {
1449 struct pte *pe = &ptes[i];
1450 pe->part_table = pt_offset(MBRbuffer, i);
1451 pe->ext_pointer = NULL;
1452 pe->offset_from_dev_start = 0;
1453 pe->sectorbuffer = MBRbuffer;
1454 #if ENABLE_FEATURE_FDISK_WRITABLE
1455 pe->changed = (what == CREATE_EMPTY_DOS);
1459 #if ENABLE_FEATURE_FDISK_WRITABLE
1460 // ALERT! highly idiotic design!
1461 // We end up here when we call get_boot() recursively
1462 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1463 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1464 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1465 // So skip opening device _again_...
1466 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1469 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1472 fd = open(disk_device, O_RDONLY);
1474 if (what == TRY_ONLY)
1476 fdisk_fatal(unable_to_open);
1478 printf("'%s' is opened for read only\n", disk_device);
1480 xmove_fd(fd, dev_fd);
1481 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1482 if (what == TRY_ONLY) {
1486 fdisk_fatal(unable_to_read);
1489 fd = open(disk_device, O_RDONLY);
1492 if (512 != full_read(fd, MBRbuffer, 512)) {
1496 xmove_fd(fd, dev_fd);
1502 #if ENABLE_FEATURE_SUN_LABEL
1503 if (check_sun_label())
1506 #if ENABLE_FEATURE_SGI_LABEL
1507 if (check_sgi_label())
1510 #if ENABLE_FEATURE_AIX_LABEL
1511 if (check_aix_label())
1514 #if ENABLE_FEATURE_GPT_LABEL
1515 if (check_gpt_label())
1518 #if ENABLE_FEATURE_OSF_LABEL
1519 if (check_osf_label()) {
1520 possibly_osf_label = 1;
1521 if (!valid_part_table_flag(MBRbuffer)) {
1522 current_label_type = LABEL_OSF;
1525 puts("This disk has both DOS and BSD magic.\n"
1526 "Give the 'b' command to go to BSD mode.");
1530 #if !ENABLE_FEATURE_FDISK_WRITABLE
1531 if (!valid_part_table_flag(MBRbuffer))
1534 if (!valid_part_table_flag(MBRbuffer)) {
1535 if (what == OPEN_MAIN) {
1536 puts("Device contains neither a valid DOS "
1537 "partition table, nor Sun, SGI, OSF or GPT "
1540 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1550 #endif /* FEATURE_FDISK_WRITABLE */
1553 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1556 for (i = 0; i < 4; i++) {
1557 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1558 if (g_partitions != 4)
1559 printf("Ignoring extra extended "
1560 "partition %u\n", i + 1);
1566 for (i = 3; i < g_partitions; i++) {
1567 struct pte *pe = &ptes[i];
1568 if (!valid_part_table_flag(pe->sectorbuffer)) {
1569 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1570 "table %u will be corrected by w(rite)\n",
1571 pe->sectorbuffer[510],
1572 pe->sectorbuffer[511],
1574 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1581 #if ENABLE_FEATURE_FDISK_WRITABLE
1583 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1584 * If the user hits Enter, DFLT is returned.
1585 * Answers like +10 are interpreted as offsets from BASE.
1587 * There is no default if DFLT is not between LOW and HIGH.
1590 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1594 const char *fmt = "%s (%u-%u, default %u): ";
1596 if (dflt < low || dflt > high) {
1597 fmt = "%s (%u-%u): ";
1602 int use_default = default_ok;
1604 /* ask question and read answer */
1606 printf(fmt, mesg, low, high, dflt);
1607 read_maybe_empty("");
1608 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1609 && *line_ptr != '-' && *line_ptr != '+');
1611 if (*line_ptr == '+' || *line_ptr == '-') {
1612 int minus = (*line_ptr == '-');
1615 value = atoi(line_ptr + 1);
1617 /* (1) if 2nd char is digit, use_default = 0.
1618 * (2) move line_ptr to first non-digit. */
1619 while (isdigit(*++line_ptr))
1622 switch (*line_ptr) {
1625 if (!display_in_cyl_units)
1626 value *= g_heads * g_sectors;
1640 absolute = 1000000000;
1649 bytes = (ullong) value * absolute;
1650 unit = sector_size * units_per_sector;
1651 bytes += unit/2; /* round */
1659 value = atoi(line_ptr);
1660 while (isdigit(*line_ptr)) {
1667 printf("Using default value %u\n", value);
1669 if (value >= low && value <= high)
1671 puts("Value is out of range");
1677 get_partition(int warn, unsigned max)
1682 i = read_int(1, 0, max, 0, "Partition number") - 1;
1686 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1687 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1688 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1690 printf("Warning: partition %u has empty type\n", i+1);
1697 get_existing_partition(int warn, unsigned max)
1702 for (i = 0; i < max; i++) {
1703 struct pte *pe = &ptes[i];
1704 struct partition *p = pe->part_table;
1706 if (p && !is_cleared_partition(p)) {
1713 printf("Selected partition %u\n", pno+1);
1716 puts("No partition is defined yet!");
1720 return get_partition(warn, max);
1724 get_nonexisting_partition(int warn, unsigned max)
1729 for (i = 0; i < max; i++) {
1730 struct pte *pe = &ptes[i];
1731 struct partition *p = pe->part_table;
1733 if (p && is_cleared_partition(p)) {
1740 printf("Selected partition %u\n", pno+1);
1743 puts("All primary partitions have been defined already!");
1747 return get_partition(warn, max);
1754 display_in_cyl_units = !display_in_cyl_units;
1756 printf("Changing display/entry units to %s\n",
1761 toggle_active(int i)
1763 struct pte *pe = &ptes[i];
1764 struct partition *p = pe->part_table;
1766 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1767 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1768 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1773 toggle_dos_compatibility_flag(void)
1775 dos_compatible_flag = 1 - dos_compatible_flag;
1776 if (dos_compatible_flag) {
1777 sector_offset = g_sectors;
1778 printf("DOS Compatibility flag is %sset\n", "");
1781 printf("DOS Compatibility flag is %sset\n", "not ");
1786 delete_partition(int i)
1788 struct pte *pe = &ptes[i];
1789 struct partition *p = pe->part_table;
1790 struct partition *q = pe->ext_pointer;
1792 /* Note that for the fifth partition (i == 4) we don't actually
1793 * decrement partitions.
1796 if (warn_geometry())
1797 return; /* C/H/S not set */
1801 sun_delete_partition(i);
1805 sgi_delete_partition(i);
1810 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1812 ptes[ext_index].ext_pointer = NULL;
1813 extended_offset = 0;
1819 if (!q->sys_ind && i > 4) {
1820 /* the last one in the chain - just delete */
1823 clear_partition(ptes[i].ext_pointer);
1824 ptes[i].changed = 1;
1826 /* not the last one - further ones will be moved down */
1828 /* delete this link in the chain */
1829 p = ptes[i-1].ext_pointer;
1831 set_start_sect(p, get_start_sect(q));
1832 set_nr_sects(p, get_nr_sects(q));
1833 ptes[i-1].changed = 1;
1834 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1835 /* the first logical in a longer chain */
1838 if (pe->part_table) /* prevent SEGFAULT */
1839 set_start_sect(pe->part_table,
1840 get_partition_start_from_dev_start(pe) -
1842 pe->offset_from_dev_start = extended_offset;
1846 if (g_partitions > 5) {
1848 while (i < g_partitions) {
1849 ptes[i] = ptes[i+1];
1853 /* the only logical: clear only */
1854 clear_partition(ptes[i].part_table);
1862 int i, sys, origsys;
1863 struct partition *p;
1865 /* If sgi_label then don't use get_existing_partition,
1866 let the user select a partition, since get_existing_partition()
1867 only works for Linux like partition tables. */
1868 if (!LABEL_IS_SGI) {
1869 i = get_existing_partition(0, g_partitions);
1871 i = get_partition(0, g_partitions);
1875 p = ptes[i].part_table;
1876 origsys = sys = get_sysid(i);
1878 /* if changing types T to 0 is allowed, then
1879 the reverse change must be allowed, too */
1880 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1881 printf("Partition %u does not exist yet!\n", i + 1);
1885 sys = read_hex(get_sys_types());
1887 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1888 puts("Type 0 means free space to many systems\n"
1889 "(but not to Linux). Having partitions of\n"
1890 "type 0 is probably unwise.");
1894 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1895 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1896 puts("You cannot change a partition into"
1897 " an extended one or vice versa");
1903 #if ENABLE_FEATURE_SUN_LABEL
1904 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1905 puts("Consider leaving partition 3 "
1906 "as Whole disk (5),\n"
1907 "as SunOS/Solaris expects it and "
1908 "even Linux likes it\n");
1910 #if ENABLE_FEATURE_SGI_LABEL
1913 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1914 (i == 8 && sys != 0)
1917 puts("Consider leaving partition 9 "
1918 "as volume header (0),\nand "
1919 "partition 11 as entire volume (6)"
1920 "as IRIX expects it\n");
1926 sun_change_sysid(i, sys);
1927 } else if (LABEL_IS_SGI) {
1928 sgi_change_sysid(i, sys);
1932 printf("Changed system type of partition %u "
1933 "to %x (%s)\n", i + 1, sys,
1934 partition_type(sys));
1935 ptes[i].changed = 1;
1936 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1942 #endif /* FEATURE_FDISK_WRITABLE */
1945 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1946 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1947 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1948 * Lubkin Oct. 1991). */
1951 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1953 int spc = g_heads * g_sectors;
1957 *h = ls / g_sectors;
1958 *s = ls % g_sectors + 1; /* sectors count from 1 */
1962 check_consistency(const struct partition *p, int partition)
1964 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1965 unsigned pec, peh, pes; /* physical ending c, h, s */
1966 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1967 unsigned lec, leh, les; /* logical ending c, h, s */
1969 if (!g_heads || !g_sectors || (partition >= 4))
1970 return; /* do not check extended partitions */
1972 /* physical beginning c, h, s */
1973 pbc = cylinder(p->sector, p->cyl);
1975 pbs = sector(p->sector);
1977 /* physical ending c, h, s */
1978 pec = cylinder(p->end_sector, p->end_cyl);
1980 pes = sector(p->end_sector);
1982 /* compute logical beginning (c, h, s) */
1983 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1985 /* compute logical ending (c, h, s) */
1986 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1988 /* Same physical / logical beginning? */
1989 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1990 printf("Partition %u has different physical/logical "
1991 "start (non-Linux?):\n", partition + 1);
1992 printf(" phys=(%u,%u,%u) ", pbc, pbh, pbs);
1993 printf("logical=(%u,%u,%u)\n", lbc, lbh, lbs);
1996 /* Same physical / logical ending? */
1997 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1998 printf("Partition %u has different physical/logical "
1999 "end:\n", partition + 1);
2000 printf(" phys=(%u,%u,%u) ", pec, peh, pes);
2001 printf("logical=(%u,%u,%u)\n", lec, leh, les);
2004 /* Ending on cylinder boundary? */
2005 if (peh != (g_heads - 1) || pes != g_sectors) {
2006 printf("Partition %u does not end on cylinder boundary\n",
2012 list_disk_geometry(void)
2014 ullong bytes = ((ullong)total_number_of_sectors << 9);
2015 ullong xbytes = bytes / (1024*1024);
2018 if (xbytes >= 10000) {
2019 xbytes += 512; /* fdisk util-linux 2.28 does this */
2023 printf("Disk %s: %llu %cB, %llu bytes, %"SECT_FMT"u sectors\n"
2024 "%u cylinders, %u heads, %u sectors/track\n"
2025 "Units: %s of %u * %u = %u bytes\n\n",
2026 disk_device, xbytes, x,
2027 bytes, total_number_of_sectors,
2028 g_cylinders, g_heads, g_sectors,
2030 units_per_sector, sector_size, units_per_sector * sector_size
2035 * Check whether partition entries are ordered by their starting positions.
2036 * Return 0 if OK. Return i if partition i should have been earlier.
2037 * Two separate checks: primary and logical partitions.
2040 wrong_p_order(int *prev)
2042 const struct pte *pe;
2043 const struct partition *p;
2044 sector_t last_p_start_pos = 0, p_start_pos;
2045 unsigned i, last_i = 0;
2047 for (i = 0; i < g_partitions; i++) {
2050 last_p_start_pos = 0;
2055 p_start_pos = get_partition_start_from_dev_start(pe);
2057 if (last_p_start_pos > p_start_pos) {
2063 last_p_start_pos = p_start_pos;
2070 #if ENABLE_FEATURE_FDISK_ADVANCED
2072 * Fix the chain of logicals.
2073 * extended_offset is unchanged, the set of sectors used is unchanged
2074 * The chain is sorted so that sectors increase, and so that
2075 * starting sectors increase.
2077 * After this it may still be that cfdisk doesnt like the table.
2078 * (This is because cfdisk considers expanded parts, from link to
2079 * end of partition, and these may still overlap.)
2081 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
2085 fix_chain_of_logicals(void)
2087 int j, oj, ojj, sj, sjj;
2088 struct partition *pj,*pjj,tmp;
2090 /* Stage 1: sort sectors but leave sector of part 4 */
2091 /* (Its sector is the global extended_offset.) */
2093 for (j = 5; j < g_partitions - 1; j++) {
2094 oj = ptes[j].offset_from_dev_start;
2095 ojj = ptes[j+1].offset_from_dev_start;
2097 ptes[j].offset_from_dev_start = ojj;
2098 ptes[j+1].offset_from_dev_start = oj;
2099 pj = ptes[j].part_table;
2100 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
2101 pjj = ptes[j+1].part_table;
2102 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
2103 set_start_sect(ptes[j-1].ext_pointer,
2104 ojj-extended_offset);
2105 set_start_sect(ptes[j].ext_pointer,
2106 oj-extended_offset);
2111 /* Stage 2: sort starting sectors */
2113 for (j = 4; j < g_partitions - 1; j++) {
2114 pj = ptes[j].part_table;
2115 pjj = ptes[j+1].part_table;
2116 sj = get_start_sect(pj);
2117 sjj = get_start_sect(pjj);
2118 oj = ptes[j].offset_from_dev_start;
2119 ojj = ptes[j+1].offset_from_dev_start;
2120 if (oj+sj > ojj+sjj) {
2124 set_start_sect(pj, ojj+sjj-oj);
2125 set_start_sect(pjj, oj+sj-ojj);
2130 /* Probably something was changed */
2131 for (j = 4; j < g_partitions; j++)
2132 ptes[j].changed = 1;
2137 fix_partition_table_order(void)
2139 struct pte *pei, *pek;
2142 if (!wrong_p_order(NULL)) {
2143 puts("Ordering is already correct\n");
2147 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2148 /* partition i should have come earlier, move it */
2149 /* We have to move data in the MBR */
2150 struct partition *pi, *pk, *pe, pbuf;
2154 pe = pei->ext_pointer;
2155 pei->ext_pointer = pek->ext_pointer;
2156 pek->ext_pointer = pe;
2158 pi = pei->part_table;
2159 pk = pek->part_table;
2161 memmove(&pbuf, pi, sizeof(struct partition));
2162 memmove(pi, pk, sizeof(struct partition));
2163 memmove(pk, &pbuf, sizeof(struct partition));
2165 pei->changed = pek->changed = 1;
2169 fix_chain_of_logicals();
2176 chs_string11(unsigned cyl, unsigned head, unsigned sect)
2178 char *buf = auto_string(xzalloc(sizeof(int)*3 * 3));
2179 sprintf(buf, "%u,%u,%u", cylinder(sect,cyl), head, sector(sect));
2184 list_table(int xtra)
2189 sun_list_table(xtra);
2193 sgi_list_table(xtra);
2197 gpt_list_table(xtra);
2201 list_disk_geometry();
2204 xbsd_print_disklabel(xtra);
2208 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2209 * but if the device name ends in a digit, say /dev/foo1,
2210 * then the partition is called /dev/foo1p3.
2212 w = strlen(disk_device);
2213 if (w && isdigit(disk_device[w-1]))
2218 printf("%-*s Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type\n",
2221 for (i = 0; i < g_partitions; i++) {
2222 const struct partition *p;
2223 const struct pte *pe = &ptes[i];
2226 sector_t start_sect;
2231 if (!p || is_cleared_partition(p))
2234 sprintf(boot4, "%02x", p->boot_ind);
2235 if ((p->boot_ind & 0x7f) == 0) {
2236 /* 0x80 shown as '*', 0x00 is ' ' */
2237 boot4[0] = p->boot_ind ? '*' : ' ';
2241 start_sect = get_partition_start_from_dev_start(pe);
2242 end_sect = start_sect;
2243 nr_sects = get_nr_sects(p);
2245 end_sect += nr_sects - 1;
2247 smart_ulltoa5((ullong)nr_sects * sector_size,
2248 numstr6, " KMGTPEZY")[0] = '\0';
2250 #define SFMT SECT_FMT
2251 // Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
2252 printf("%s%s %-11s"/**/" %-11s"/**/" %10"SFMT"u %10"SFMT"u %10"SFMT"u %s %2x %s\n",
2253 partname(disk_device, i+1, w+2),
2255 chs_string11(p->cyl, p->head, p->sector),
2256 chs_string11(p->end_cyl, p->end_head, p->end_sector),
2262 partition_type(p->sys_ind)
2265 check_consistency(p, i);
2268 /* Is partition table in disk order? It need not be, but... */
2269 /* partition table entries are not checked for correct order
2270 * if this is a sgi, sun or aix labeled disk... */
2271 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2273 puts("\nPartition table entries are not in disk order");
2277 #if ENABLE_FEATURE_FDISK_ADVANCED
2279 x_list_table(int extend)
2281 const struct pte *pe;
2282 const struct partition *p;
2285 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2286 disk_device, g_heads, g_sectors, g_cylinders);
2287 puts("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID");
2288 for (i = 0; i < g_partitions; i++) {
2290 p = (extend ? pe->ext_pointer : pe->part_table);
2292 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2296 cylinder(p->sector, p->cyl),
2298 sector(p->end_sector),
2299 cylinder(p->end_sector, p->end_cyl),
2305 check_consistency(p, i);
2311 #if ENABLE_FEATURE_FDISK_WRITABLE
2313 fill_bounds(sector_t *first, sector_t *last)
2316 const struct pte *pe = &ptes[0];
2317 const struct partition *p;
2319 for (i = 0; i < g_partitions; pe++,i++) {
2321 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2322 first[i] = 0xffffffff;
2325 first[i] = get_partition_start_from_dev_start(pe);
2326 last[i] = first[i] + get_nr_sects(p) - 1;
2332 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2334 sector_t total, real_s, real_c;
2336 real_s = sector(s) - 1;
2337 real_c = cylinder(s, c);
2338 total = (real_c * g_sectors + real_s) * g_heads + h;
2340 printf("Partition %u contains sector 0\n", n);
2342 printf("Partition %u: head %u greater than maximum %u\n",
2344 if (real_s >= g_sectors)
2345 printf("Partition %u: sector %u greater than "
2346 "maximum %u\n", n, s, g_sectors);
2347 if (real_c >= g_cylinders)
2348 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2349 "maximum %u\n", n, real_c + 1, g_cylinders);
2350 if (g_cylinders <= 1024 && start != total)
2351 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2352 "total %"SECT_FMT"u\n", n, start, total);
2361 sector_t first[g_partitions], last[g_partitions];
2362 struct partition *p;
2364 if (warn_geometry())
2376 fill_bounds(first, last);
2377 for (i = 0; i < g_partitions; i++) {
2378 struct pte *pe = &ptes[i];
2381 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2382 check_consistency(p, i);
2383 if (get_partition_start_from_dev_start(pe) < first[i])
2384 printf("Warning: bad start-of-data in "
2385 "partition %u\n", i + 1);
2386 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2388 total += last[i] + 1 - first[i];
2389 for (j = 0; j < i; j++) {
2390 if ((first[i] >= first[j] && first[i] <= last[j])
2391 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2392 printf("Warning: partition %u overlaps "
2393 "partition %u\n", j + 1, i + 1);
2394 total += first[i] >= first[j] ?
2395 first[i] : first[j];
2396 total -= last[i] <= last[j] ?
2403 if (extended_offset) {
2404 struct pte *pex = &ptes[ext_index];
2405 sector_t e_last = get_start_sect(pex->part_table) +
2406 get_nr_sects(pex->part_table) - 1;
2408 for (i = 4; i < g_partitions; i++) {
2410 p = ptes[i].part_table;
2412 if (i != 4 || i + 1 < g_partitions)
2413 printf("Warning: partition %u "
2414 "is empty\n", i + 1);
2415 } else if (first[i] < extended_offset || last[i] > e_last) {
2416 printf("Logical partition %u not entirely in "
2417 "partition %u\n", i + 1, ext_index + 1);
2422 chs_size = (sector_t)g_heads * g_sectors * g_cylinders;
2423 if (total > chs_size)
2424 printf("Total allocated sectors %u"
2425 " greater than CHS size %"SECT_FMT"u\n",
2429 total = chs_size - total;
2431 printf("%"SECT_FMT"u unallocated sectors\n", total);
2436 add_partition(int n, int sys)
2438 char mesg[256]; /* 48 does not suffice in Japanese */
2439 int i, num_read = 0;
2440 struct partition *p = ptes[n].part_table;
2441 struct partition *q = ptes[ext_index].part_table;
2442 sector_t limit, temp;
2443 sector_t start, stop = 0;
2444 sector_t first[g_partitions], last[g_partitions];
2446 if (p && p->sys_ind) {
2447 printf(msg_part_already_defined, n + 1);
2450 fill_bounds(first, last);
2452 start = sector_offset;
2453 if (display_in_cyl_units || !total_number_of_sectors)
2454 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2456 limit = total_number_of_sectors - 1;
2457 if (extended_offset) {
2458 first[ext_index] = extended_offset;
2459 last[ext_index] = get_start_sect(q) +
2460 get_nr_sects(q) - 1;
2463 start = extended_offset + sector_offset;
2464 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2466 if (display_in_cyl_units)
2467 for (i = 0; i < g_partitions; i++)
2468 first[i] = (cround(first[i]) - 1) * units_per_sector;
2470 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2473 for (i = 0; i < g_partitions; i++) {
2476 if (start == ptes[i].offset_from_dev_start)
2477 start += sector_offset;
2478 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2479 if (start >= first[i] && start <= lastplusoff)
2480 start = lastplusoff + 1;
2484 if (start >= temp+units_per_sector && num_read) {
2485 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2489 if (!num_read && start == temp) {
2490 sector_t saved_start;
2492 saved_start = start;
2493 start = read_int(cround(saved_start), cround(saved_start), cround(limit), 0, mesg);
2494 if (display_in_cyl_units) {
2495 start = (start - 1) * units_per_sector;
2496 if (start < saved_start)
2497 start = saved_start;
2501 } while (start != temp || !num_read);
2502 if (n > 4) { /* NOT for fifth partition */
2503 struct pte *pe = &ptes[n];
2505 pe->offset_from_dev_start = start - sector_offset;
2506 if (pe->offset_from_dev_start == extended_offset) { /* must be corrected */
2507 pe->offset_from_dev_start++;
2508 if (sector_offset == 1)
2513 for (i = 0; i < g_partitions; i++) {
2514 struct pte *pe = &ptes[i];
2516 if (start < pe->offset_from_dev_start && limit >= pe->offset_from_dev_start)
2517 limit = pe->offset_from_dev_start - 1;
2518 if (start < first[i] && limit >= first[i])
2519 limit = first[i] - 1;
2521 if (start > limit) {
2522 puts("No free sectors available");
2527 if (cround(start) == cround(limit)) {
2530 snprintf(mesg, sizeof(mesg),
2531 "Last %s or +size or +sizeM or +sizeK",
2532 str_units(SINGULAR));
2533 stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg);
2534 if (display_in_cyl_units) {
2535 stop = stop * units_per_sector - 1;
2541 set_partition(n, 0, start, stop, sys);
2543 set_partition(n - 1, 1, ptes[n].offset_from_dev_start, stop, EXTENDED);
2545 if (IS_EXTENDED(sys)) {
2546 struct pte *pe4 = &ptes[4];
2547 struct pte *pen = &ptes[n];
2550 pen->ext_pointer = p;
2551 pe4->offset_from_dev_start = extended_offset = start;
2552 pe4->sectorbuffer = xzalloc(sector_size);
2553 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2554 pe4->ext_pointer = pe4->part_table + 1;
2563 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2564 struct pte *pe = &ptes[g_partitions];
2566 pe->sectorbuffer = xzalloc(sector_size);
2567 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2568 pe->ext_pointer = pe->part_table + 1;
2569 pe->offset_from_dev_start = 0;
2573 add_partition(g_partitions - 1, LINUX_NATIVE);
2579 int i, free_primary = 0;
2581 if (warn_geometry())
2585 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2589 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2593 puts("Sorry - this fdisk cannot handle AIX disk labels.\n"
2594 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2595 "table first (use 'o'). This will destroy the present disk contents.");
2599 for (i = 0; i < 4; i++)
2600 free_primary += !ptes[i].part_table->sys_ind;
2602 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2603 puts("The maximum number of partitions has been created");
2607 if (!free_primary) {
2608 if (extended_offset)
2611 puts("You must delete some partition and add "
2612 "an extended partition first");
2615 snprintf(line, sizeof(line),
2618 " p primary partition (1-4)\n",
2620 "l logical (5 or over)" : "e extended"));
2622 c = read_nonempty(line);
2623 if ((c | 0x20) == 'p') {
2624 i = get_nonexisting_partition(0, 4);
2626 add_partition(i, LINUX_NATIVE);
2629 if (c == 'l' && extended_offset) {
2633 if (c == 'e' && !extended_offset) {
2634 i = get_nonexisting_partition(0, 4);
2636 add_partition(i, EXTENDED);
2639 printf("Invalid partition number "
2640 "for type '%c'\n", c);
2646 reread_partition_table(int leave)
2650 puts("Calling ioctl() to re-read partition table");
2652 /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
2653 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
2656 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2657 "WARNING: rereading partition table "
2658 "failed, kernel still uses old table");
2662 "\nWARNING: If you have created or modified any DOS 6.x\n"
2663 "partitions, please see the fdisk manual page for additional\n"
2668 if (ENABLE_FEATURE_CLEAN_UP)
2680 for (i = 0; i < 3; i++)
2681 if (ptes[i].changed)
2682 ptes[3].changed = 1;
2683 for (i = 3; i < g_partitions; i++) {
2684 struct pte *pe = &ptes[i];
2686 write_part_table_flag(pe->sectorbuffer);
2687 write_sector(pe->offset_from_dev_start, pe->sectorbuffer);
2691 else if (LABEL_IS_SGI) {
2692 /* no test on change? the "altered" msg below might be mistaken */
2695 else if (LABEL_IS_SUN) {
2696 for (i = 0; i < 8; i++) {
2697 if (ptes[i].changed) {
2704 puts("The partition table has been altered.");
2705 reread_partition_table(1);
2707 #endif /* FEATURE_FDISK_WRITABLE */
2709 #if ENABLE_FEATURE_FDISK_ADVANCED
2710 #define MAX_PER_LINE 16
2712 print_buffer(char *pbuffer)
2716 for (i = 0, l = 0; i < sector_size; i++, l++) {
2718 printf("0x%03X:", i);
2719 printf(" %02X", (unsigned char) pbuffer[i]);
2720 if (l == MAX_PER_LINE - 1) {
2735 printf("Device: %s\n", disk_device);
2736 if (LABEL_IS_SGI || LABEL_IS_SUN)
2737 print_buffer(MBRbuffer);
2739 for (i = 3; i < g_partitions; i++)
2740 print_buffer(ptes[i].sectorbuffer);
2745 move_begin(unsigned i)
2747 struct pte *pe = &ptes[i];
2748 struct partition *p = pe->part_table;
2749 sector_t new, first, nr_sects;
2751 if (warn_geometry())
2753 nr_sects = get_nr_sects(p);
2754 if (!p->sys_ind || !nr_sects || IS_EXTENDED(p->sys_ind)) {
2755 printf("Partition %u has no data area\n", i + 1);
2758 first = get_partition_start_from_dev_start(pe); /* == pe->offset_from_dev_start + get_start_sect(p) */
2759 new = read_int(0 /*was:first*/, first, first + nr_sects - 1, first, "New beginning of data");
2761 sector_t new_relative = new - pe->offset_from_dev_start;
2762 nr_sects += (get_start_sect(p) - new_relative);
2763 set_start_sect(p, new_relative);
2764 set_nr_sects(p, nr_sects);
2765 read_nonempty("Recalculate C/H/S values? (Y/N): ");
2766 if ((line_ptr[0] | 0x20) == 'y')
2767 set_hsc_start_end(p, new, new + nr_sects - 1);
2779 c = 0x20 | read_nonempty("Expert command (m for help): ");
2787 move_begin(get_partition(0, g_partitions));
2790 user_cylinders = g_cylinders =
2791 read_int(1, g_cylinders, 1048576, 0,
2792 "Number of cylinders");
2794 sun_set_ncyl(g_cylinders);
2804 else if (LABEL_IS_SUN)
2806 else if (LABEL_IS_DOS)
2811 fix_partition_table_order();
2814 #if ENABLE_FEATURE_SGI_LABEL
2819 user_heads = g_heads = read_int(1, g_heads, 256, 0, "Number of heads");
2837 if (ENABLE_FEATURE_CLEAN_UP)
2844 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors");
2845 if (dos_compatible_flag) {
2846 sector_offset = g_sectors;
2847 puts("Warning: setting sector offset for DOS "
2856 write_table(); /* does not return */
2860 sun_set_pcylcount();
2867 #endif /* ADVANCED mode */
2870 is_ide_cdrom_or_tape(const char *device)
2874 struct stat statbuf;
2877 /* No device was given explicitly, and we are trying some
2878 likely things. But opening /dev/hdc may produce errors like
2879 "hdc: tray open or drive not ready"
2880 if it happens to be a CD-ROM drive. It even happens that
2881 the process hangs on the attempt to read a music CD.
2882 So try to be careful. This only works since 2.1.73. */
2884 if (!is_prefixed_with(device, "/dev/hd"))
2887 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2888 procf = fopen_for_read(buf);
2889 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2890 is_ide = (is_prefixed_with(buf, "cdrom") ||
2891 is_prefixed_with(buf, "tape"));
2893 /* Now when this proc file does not exist, skip the
2894 device when it is read-only. */
2895 if (stat(device, &statbuf) == 0)
2896 is_ide = ((statbuf.st_mode & 0222) == 0);
2905 open_list_and_close(const char *device, int user_specified)
2909 disk_device = device;
2910 if (setjmp(listingbuf))
2912 if (!user_specified)
2913 if (is_ide_cdrom_or_tape(device))
2916 /* Open disk_device, save file descriptor to dev_fd */
2918 gb = get_boot(TRY_ONLY);
2919 if (gb > 0) { /* I/O error */
2920 /* Ignore other errors, since we try IDE
2921 and SCSI hard disks which may not be
2922 installed on the system. */
2923 if (user_specified || errno == EACCES)
2924 bb_perror_msg("can't open '%s'", device);
2928 if (gb < 0) { /* no DOS signature */
2929 list_disk_geometry();
2932 #if ENABLE_FEATURE_OSF_LABEL
2933 if (bsd_trydev(device) < 0)
2935 printf("Disk %s doesn't contain a valid "
2936 "partition table\n", device);
2939 #if ENABLE_FEATURE_FDISK_WRITABLE
2940 if (!LABEL_IS_SUN && g_partitions > 4) {
2941 delete_partition(ext_index);
2949 /* Is it a whole disk? The digit check is still useful
2950 for Xen devices for example. */
2951 static int is_whole_disk(const char *disk)
2954 int fd = open(disk, O_RDONLY);
2957 struct hd_geometry geometry;
2958 int err = ioctl(fd, HDIO_GETGEO, &geometry);
2961 return (geometry.start == 0);
2964 /* Treat "nameN" as a partition name, not whole disk */
2965 /* note: mmcblk0 should work from the geometry check above */
2967 if (len != 0 && isdigit(disk[len - 1]))
2973 /* for fdisk -l: try all things in /proc/partitions
2974 that look like a partition name (do not end in a digit) */
2976 list_devs_in_proc_partititons(void)
2979 char line[100], ptname[100], devname[120];
2982 procpt = fopen_or_warn("/proc/partitions", "r");
2984 while (fgets(line, sizeof(line), procpt)) {
2985 if (sscanf(line, " %u %u %u %[^\n ]",
2986 &ma, &mi, &sz, ptname) != 4)
2989 sprintf(devname, "/dev/%s", ptname);
2990 if (is_whole_disk(devname))
2991 open_list_and_close(devname, 0);
2993 #if ENABLE_FEATURE_CLEAN_UP
2998 #if ENABLE_FEATURE_FDISK_WRITABLE
3000 unknown_command(int c)
3002 printf("%c: unknown command\n", c);
3006 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
3007 int fdisk_main(int argc UNUSED_PARAM, char **argv)
3012 * fdisk -l [-b sectorsize] [-u] device ...
3013 * fdisk -s [partition] ...
3014 * fdisk [-b sectorsize] [-u] device
3016 * Options -C, -H, -S set the geometry.
3020 close_dev_fd(); /* needed: fd 3 must not stay closed */
3022 opt = getopt32(argv, "b:+C:+H:+lS:+u" IF_FEATURE_FDISK_BLKSIZE("s"),
3023 §or_size, &user_cylinders, &user_heads, &user_sectors);
3026 /* Ugly: this sector size is really per device,
3027 * so cannot be combined with multiple disks,
3028 * and the same goes for the C/H/S options.
3030 if (sector_size < 512
3031 || sector_size > 0x10000
3032 || (sector_size & (sector_size-1)) /* not power of 2 */
3037 user_set_sector_size = 1;
3039 if (user_heads <= 0 || user_heads >= 256)
3041 if (user_sectors <= 0 || user_sectors >= 64)
3044 display_in_cyl_units = 0; // -u
3046 #if ENABLE_FEATURE_FDISK_WRITABLE
3053 open_list_and_close(*argv, 1);
3056 /* we don't have device names, */
3057 /* use /proc/partitions instead */
3058 list_devs_in_proc_partititons();
3061 #if ENABLE_FEATURE_FDISK_WRITABLE
3065 #if ENABLE_FEATURE_FDISK_BLKSIZE
3072 for (j = 0; argv[j]; j++) {
3073 unsigned long long size;
3074 fd = xopen(argv[j], O_RDONLY);
3075 size = bb_BLKGETSIZE_sectors(fd) / 2;
3078 printf("%llu\n", size);
3080 printf("%s: %llu\n", argv[j], size);
3086 #if ENABLE_FEATURE_FDISK_WRITABLE
3087 if (!argv[0] || argv[1])
3090 disk_device = argv[0];
3091 get_boot(OPEN_MAIN);
3094 /* OSF label, and no DOS label */
3095 printf("Detected an OSF/1 disklabel on %s, entering "
3096 "disklabel mode\n", disk_device);
3098 /*Why do we do this? It seems to be counter-intuitive*/
3099 current_label_type = LABEL_DOS;
3100 /* If we return we may want to make an empty DOS label? */
3106 c = 0x20 | read_nonempty("Command (m for help): ");
3110 toggle_active(get_partition(1, g_partitions));
3111 else if (LABEL_IS_SUN)
3112 toggle_sunflags(get_partition(1, g_partitions),
3114 else if (LABEL_IS_SGI)
3115 sgi_set_bootpartition(
3116 get_partition(1, g_partitions));
3122 printf("\nThe current boot file is: %s\n",
3123 sgi_get_bootfile());
3124 if (read_maybe_empty("Please enter the name of the "
3125 "new boot file: ") == '\n')
3126 puts("Boot file unchanged");
3128 sgi_set_bootfile(line_ptr);
3130 #if ENABLE_FEATURE_OSF_LABEL
3137 toggle_dos_compatibility_flag();
3138 else if (LABEL_IS_SUN)
3139 toggle_sunflags(get_partition(1, g_partitions),
3141 else if (LABEL_IS_SGI)
3142 sgi_set_swappartition(
3143 get_partition(1, g_partitions));
3150 /* If sgi_label then don't use get_existing_partition,
3151 let the user select a partition, since
3152 get_existing_partition() only works for Linux-like
3154 if (!LABEL_IS_SGI) {
3155 j = get_existing_partition(1, g_partitions);
3157 j = get_partition(1, g_partitions);
3160 delete_partition(j);
3169 list_types(get_sys_types());
3184 if (ENABLE_FEATURE_CLEAN_UP)
3189 #if ENABLE_FEATURE_SUN_LABEL
3203 write_table(); /* does not return */
3205 #if ENABLE_FEATURE_FDISK_ADVANCED
3208 puts("\n\tSorry, no experts menu for SGI "
3209 "partition tables available\n");
3220 #endif /* FEATURE_FDISK_WRITABLE */