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 /* Looks like someone forgot to add this to config system */
11 //usage:#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
12 //usage:# define ENABLE_FEATURE_FDISK_BLKSIZE 0
13 //usage:# define IF_FEATURE_FDISK_BLKSIZE(a)
16 //usage:#define fdisk_trivial_usage
17 //usage: "[-ul" IF_FEATURE_FDISK_BLKSIZE("s") "] "
18 //usage: "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK"
19 //usage:#define fdisk_full_usage "\n\n"
20 //usage: "Change partition table\n"
21 //usage: "\n -u Start and End are in sectors (instead of cylinders)"
22 //usage: "\n -l Show partition table for each DISK, then exit"
23 //usage: IF_FEATURE_FDISK_BLKSIZE(
24 //usage: "\n -s Show partition sizes in kb for each DISK, then exit"
26 //usage: "\n -b 2048 (for certain MO disks) use 2048-byte sectors"
27 //usage: "\n -C CYLINDERS Set number of cylinders/heads/sectors"
28 //usage: "\n -H HEADS"
29 //usage: "\n -S SECTORS"
31 #ifndef _LARGEFILE64_SOURCE
33 # define _LARGEFILE64_SOURCE
35 #include <assert.h> /* assert */
36 #include <sys/mount.h>
37 #if !defined(BLKSSZGET)
38 # define BLKSSZGET _IO(0x12, 104)
40 #if !defined(BLKGETSIZE64)
41 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
46 # define inline_if_little_endian ALWAYS_INLINE
48 # define inline_if_little_endian /* nothing */
52 /* Looks like someone forgot to add this to config system */
53 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
54 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
55 # define IF_FEATURE_FDISK_BLKSIZE(a)
58 #define DEFAULT_SECTOR_SIZE 512
59 #define DEFAULT_SECTOR_SIZE_STR "512"
60 #define MAX_SECTOR_SIZE 2048
61 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
62 #define MAXIMUM_PARTS 60
64 #define ACTIVE_FLAG 0x80
67 #define WIN98_EXTENDED 0x0f
68 #define LINUX_PARTITION 0x81
69 #define LINUX_SWAP 0x82
70 #define LINUX_NATIVE 0x83
71 #define LINUX_EXTENDED 0x85
72 #define LINUX_LVM 0x8e
73 #define LINUX_RAID 0xfd
83 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
87 typedef unsigned long long ullong;
88 /* Used for sector numbers. Partition formats we know
89 * do not support more than 2^32 sectors
91 typedef uint32_t sector_t;
92 #if UINT_MAX == 4294967295
94 #elif ULONG_MAX == 4294967295
97 # error Cant detect sizeof(uint32_t)
102 unsigned char sectors;
103 unsigned short cylinders;
107 #define HDIO_GETGEO 0x0301 /* get device geometry */
109 static const char msg_building_new_label[] ALIGN1 =
110 "Building a new %s. Changes will remain in memory only,\n"
111 "until you decide to write them. After that the previous content\n"
112 "won't be recoverable.\n\n";
114 static const char msg_part_already_defined[] ALIGN1 =
115 "Partition %u is already defined, delete it before re-adding\n";
119 unsigned char boot_ind; /* 0x80 - active */
120 unsigned char head; /* starting head */
121 unsigned char sector; /* starting sector */
122 unsigned char cyl; /* starting cylinder */
123 unsigned char sys_ind; /* what partition type */
124 unsigned char end_head; /* end head */
125 unsigned char end_sector; /* end sector */
126 unsigned char end_cyl; /* end cylinder */
127 unsigned char start4[4]; /* starting sector counting from 0 */
128 unsigned char size4[4]; /* nr of sectors in partition */
132 * per partition table entry data
134 * The four primary partitions have the same sectorbuffer (MBRbuffer)
135 * and have NULL ext_pointer.
136 * Each logical partition table entry has two pointers, one for the
137 * partition and one link to the next one.
140 struct partition *part_table; /* points into sectorbuffer */
141 struct partition *ext_pointer; /* points into sectorbuffer */
142 sector_t offset_from_dev_start; /* disk sector number */
143 char *sectorbuffer; /* disk sector contents */
144 #if ENABLE_FEATURE_FDISK_WRITABLE
145 char changed; /* boolean */
149 #define unable_to_open "can't open '%s'"
150 #define unable_to_read "can't read from %s"
151 #define unable_to_seek "can't seek on %s"
154 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT
157 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
159 #if ENABLE_FEATURE_SUN_LABEL
160 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
161 #define STATIC_SUN static
163 #define LABEL_IS_SUN 0
164 #define STATIC_SUN extern
167 #if ENABLE_FEATURE_SGI_LABEL
168 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
169 #define STATIC_SGI static
171 #define LABEL_IS_SGI 0
172 #define STATIC_SGI extern
175 #if ENABLE_FEATURE_AIX_LABEL
176 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
177 #define STATIC_AIX static
179 #define LABEL_IS_AIX 0
180 #define STATIC_AIX extern
183 #if ENABLE_FEATURE_OSF_LABEL
184 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
185 #define STATIC_OSF static
187 #define LABEL_IS_OSF 0
188 #define STATIC_OSF extern
191 #if ENABLE_FEATURE_GPT_LABEL
192 #define LABEL_IS_GPT (LABEL_GPT == current_label_type)
193 #define STATIC_GPT static
195 #define LABEL_IS_GPT 0
196 #define STATIC_GPT extern
199 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
201 static void update_units(void);
202 #if ENABLE_FEATURE_FDISK_WRITABLE
203 static void change_units(void);
204 static void reread_partition_table(int leave);
205 static void delete_partition(int i);
206 static unsigned get_partition(int warn, unsigned max);
207 static void list_types(const char *const *sys);
208 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
210 static const char *partition_type(unsigned char type);
211 static void get_geometry(void);
212 static void read_pte(struct pte *pe, sector_t offset);
213 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
214 static int get_boot(enum action what);
216 static int get_boot(void);
222 static sector_t get_start_sect(const struct partition *p);
223 static sector_t get_nr_sects(const struct partition *p);
225 /* DOS partition types */
227 static const char *const i386_sys_types[] = {
231 "\x05" "Extended", /* DOS 3.3+ extended partition */
232 "\x06" "FAT16", /* DOS 16-bit >=32M */
233 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
234 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
235 "\x0b" "Win95 FAT32",
236 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
237 "\x0e" "Win95 FAT16 (LBA)",
238 "\x0f" "Win95 Ext'd (LBA)",
239 "\x11" "Hidden FAT12",
240 "\x12" "Compaq diagnostics",
241 "\x14" "Hidden FAT16 <32M",
242 "\x16" "Hidden FAT16",
243 "\x17" "Hidden HPFS/NTFS",
244 "\x1b" "Hidden Win95 FAT32",
245 "\x1c" "Hidden W95 FAT32 (LBA)",
246 "\x1e" "Hidden W95 FAT16 (LBA)",
247 "\x3c" "Part.Magic recovery",
248 "\x41" "PPC PReP Boot",
250 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
251 "\x80" "Old Minix", /* Minix 1.4a and earlier */
252 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
253 "\x82" "Linux swap", /* also Solaris */
255 "\x84" "OS/2 hidden C: drive",
256 "\x85" "Linux extended",
257 "\x86" "NTFS volume set",
258 "\x87" "NTFS volume set",
260 "\x9f" "BSD/OS", /* BSDI */
261 "\xa0" "Thinkpad hibernation",
262 "\xa5" "FreeBSD", /* various BSD flavours */
266 "\xab" "Darwin boot",
269 "\xbe" "Solaris boot",
271 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
272 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
273 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
274 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
275 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
276 autodetect using persistent
278 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
281 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
282 "\x09" "AIX bootable", /* AIX data or Coherent */
284 "\x18" "AST SmartSleep",
287 "\x40" "Venix 80286",
289 "\x4e" "QNX4.x 2nd part",
290 "\x4f" "QNX4.x 3rd part",
292 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
293 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
294 "\x53" "OnTrack DM6 Aux3",
298 "\x5c" "Priam Edisk",
300 "\x64" "Novell Netware 286",
301 "\x65" "Novell Netware 386",
302 "\x70" "DiskSecure Multi-Boot",
305 "\x94" "Amoeba BBT", /* (bad block table) */
307 "\xbb" "Boot Wizard hidden",
308 "\xc1" "DRDOS/sec (FAT-12)",
309 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
310 "\xc6" "DRDOS/sec (FAT-16)",
312 "\xda" "Non-FS data",
313 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
314 Concurrent DOS or CTOS */
315 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
316 "\xdf" "BootIt", /* BootIt EMBRM */
317 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
318 extended partition */
319 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
320 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
321 partition < 1024 cyl. */
323 "\xf4" "SpeedStor", /* SpeedStor large partition */
324 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
325 "\xff" "BBT", /* Xenix Bad Block Table */
331 dev_fd = 3 /* the disk */
338 const char *disk_device;
339 int g_partitions; // = 4; /* maximum partition + 1 */
340 unsigned units_per_sector; // = 1;
341 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
342 unsigned user_set_sector_size;
343 unsigned sector_offset; // = 1;
344 unsigned g_heads, g_sectors, g_cylinders;
345 smallint /* enum label_type */ current_label_type;
346 smallint display_in_cyl_units; // = 1;
347 #if ENABLE_FEATURE_OSF_LABEL
348 smallint possibly_osf_label;
351 smallint listing; /* no aborts for fdisk -l */
352 smallint dos_compatible_flag; // = 1;
353 #if ENABLE_FEATURE_FDISK_WRITABLE
355 smallint nowarn; /* no warnings for fdisk -l/-s */
357 int ext_index; /* the prime extended partition */
358 unsigned user_cylinders, user_heads, user_sectors;
359 unsigned pt_heads, pt_sectors;
360 unsigned kern_heads, kern_sectors;
361 sector_t extended_offset; /* offset of link pointers */
362 sector_t total_number_of_sectors;
365 char line_buffer[80];
366 /* Raw disk label. For DOS-type partition tables the MBR,
367 * with descriptions of the primary partitions. */
368 char MBRbuffer[MAX_SECTOR_SIZE];
369 /* Partition tables */
370 struct pte ptes[MAXIMUM_PARTS];
372 #define G (*ptr_to_globals)
373 #define line_ptr (G.line_ptr )
374 #define disk_device (G.disk_device )
375 #define g_partitions (G.g_partitions )
376 #define units_per_sector (G.units_per_sector )
377 #define sector_size (G.sector_size )
378 #define user_set_sector_size (G.user_set_sector_size)
379 #define sector_offset (G.sector_offset )
380 #define g_heads (G.g_heads )
381 #define g_sectors (G.g_sectors )
382 #define g_cylinders (G.g_cylinders )
383 #define current_label_type (G.current_label_type )
384 #define display_in_cyl_units (G.display_in_cyl_units)
385 #define possibly_osf_label (G.possibly_osf_label )
386 #define listing (G.listing )
387 #define dos_compatible_flag (G.dos_compatible_flag )
388 #define nowarn (G.nowarn )
389 #define ext_index (G.ext_index )
390 #define user_cylinders (G.user_cylinders )
391 #define user_heads (G.user_heads )
392 #define user_sectors (G.user_sectors )
393 #define pt_heads (G.pt_heads )
394 #define pt_sectors (G.pt_sectors )
395 #define kern_heads (G.kern_heads )
396 #define kern_sectors (G.kern_sectors )
397 #define extended_offset (G.extended_offset )
398 #define total_number_of_sectors (G.total_number_of_sectors)
399 #define listingbuf (G.listingbuf )
400 #define line_buffer (G.line_buffer )
401 #define MBRbuffer (G.MBRbuffer )
402 #define ptes (G.ptes )
403 #define INIT_G() do { \
404 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
405 sector_size = DEFAULT_SECTOR_SIZE; \
408 display_in_cyl_units = 1; \
409 units_per_sector = 1; \
410 dos_compatible_flag = 1; \
414 /* TODO: move to libbb? */
415 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
416 * disks > 2^32 sectors
418 static sector_t bb_BLKGETSIZE_sectors(int fd)
421 unsigned long longsectors;
423 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
424 /* Got bytes, convert to 512 byte sectors */
426 if (v64 != (sector_t)v64) {
428 /* Not only DOS, but all other partition tables
429 * we support can't record more than 32 bit
430 * sector counts or offsets
432 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
437 /* Needs temp of type long */
438 if (ioctl(fd, BLKGETSIZE, &longsectors)) {
439 /* Perhaps this is a disk image */
440 off_t sz = lseek(fd, 0, SEEK_END);
443 longsectors = (uoff_t)sz / sector_size;
444 lseek(fd, 0, SEEK_SET);
446 if (sizeof(long) > sizeof(sector_t)
447 && longsectors != (sector_t)longsectors
455 #define IS_EXTENDED(i) \
456 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
458 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
460 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
462 #define pt_offset(b, n) \
463 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
465 #define sector(s) ((s) & 0x3f)
467 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
472 /* Not really closing, but making sure it is open, and to harmless place */
473 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
476 static ALWAYS_INLINE struct partition *
477 get_part_table(int i)
479 return ptes[i].part_table;
484 { /* n==1: use singular */
486 return display_in_cyl_units ? "cylinder" : "sector";
487 return display_in_cyl_units ? "cylinders" : "sectors";
491 valid_part_table_flag(const char *mbuffer)
493 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
496 static void fdisk_fatal(const char *why)
500 longjmp(listingbuf, 1);
502 bb_error_msg_and_die(why, disk_device);
506 seek_sector(sector_t secno)
508 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
509 off64_t off = (off64_t)secno * sector_size;
510 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
511 fdisk_fatal(unable_to_seek);
513 uint64_t off = (uint64_t)secno * sector_size;
514 if (off > MAXINT(off_t)
515 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
517 fdisk_fatal(unable_to_seek);
522 #if ENABLE_FEATURE_FDISK_WRITABLE
523 /* Read line; return 0 or first printable char */
525 read_line(const char *prompt)
529 sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
531 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
533 if (line_buffer[sz-1] == '\n')
534 line_buffer[--sz] = '\0';
536 line_ptr = line_buffer;
537 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
543 set_all_unchanged(void)
547 for (i = 0; i < MAXIMUM_PARTS; i++)
551 static ALWAYS_INLINE void
557 static ALWAYS_INLINE void
558 write_part_table_flag(char *b)
565 read_nonempty(const char *mesg)
567 while (!read_line(mesg))
573 read_maybe_empty(const char *mesg)
575 if (!read_line(mesg)) {
576 line_ptr = line_buffer;
584 read_hex(const char *const *sys)
588 read_nonempty("Hex code (type L to list codes): ");
589 if ((line_ptr[0] | 0x20) == 'l') {
593 v = bb_strtoul(line_ptr, NULL, 16);
600 write_sector(sector_t secno, const void *buf)
603 xwrite(dev_fd, buf, sector_size);
605 #endif /* FEATURE_FDISK_WRITABLE */
608 #include "fdisk_aix.c"
610 struct sun_partition {
611 unsigned char info[128]; /* Informative text string */
612 unsigned char spare0[14];
614 unsigned char spare1;
616 unsigned char spare2;
619 unsigned char spare1[246]; /* Boot information etc. */
620 unsigned short rspeed; /* Disk rotational speed */
621 unsigned short pcylcount; /* Physical cylinder count */
622 unsigned short sparecyl; /* extra sects per cylinder */
623 unsigned char spare2[4]; /* More magic... */
624 unsigned short ilfact; /* Interleave factor */
625 unsigned short ncyl; /* Data cylinder count */
626 unsigned short nacyl; /* Alt. cylinder count */
627 unsigned short ntrks; /* Tracks per cylinder */
628 unsigned short nsect; /* Sectors per track */
629 unsigned char spare3[4]; /* Even more magic... */
630 struct sun_partinfo {
631 uint32_t start_cylinder;
632 uint32_t num_sectors;
634 unsigned short magic; /* Magic number */
635 unsigned short csum; /* Label xor'd checksum */
637 typedef struct sun_partition sun_partition;
638 #define sunlabel ((sun_partition *)MBRbuffer)
639 STATIC_OSF void bsd_select(void);
640 STATIC_OSF void xbsd_print_disklabel(int);
641 #include "fdisk_osf.c"
643 STATIC_GPT void gpt_list_table(int xtra);
644 #include "fdisk_gpt.c"
646 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
648 fdisk_swap16(uint16_t x)
650 return (x << 8) | (x >> 8);
654 fdisk_swap32(uint32_t x)
657 ((x & 0xFF00) << 8) |
658 ((x & 0xFF0000) >> 8) |
663 STATIC_SGI const char *const sgi_sys_types[];
664 STATIC_SGI unsigned sgi_get_num_sectors(int i);
665 STATIC_SGI int sgi_get_sysid(int i);
666 STATIC_SGI void sgi_delete_partition(int i);
667 STATIC_SGI void sgi_change_sysid(int i, int sys);
668 STATIC_SGI void sgi_list_table(int xtra);
669 #if ENABLE_FEATURE_FDISK_ADVANCED
670 STATIC_SGI void sgi_set_xcyl(void);
672 STATIC_SGI int verify_sgi(int verbose);
673 STATIC_SGI void sgi_add_partition(int n, int sys);
674 STATIC_SGI void sgi_set_swappartition(int i);
675 STATIC_SGI const char *sgi_get_bootfile(void);
676 STATIC_SGI void sgi_set_bootfile(const char* aFile);
677 STATIC_SGI void create_sgiinfo(void);
678 STATIC_SGI void sgi_write_table(void);
679 STATIC_SGI void sgi_set_bootpartition(int i);
680 #include "fdisk_sgi.c"
682 STATIC_SUN const char *const sun_sys_types[];
683 STATIC_SUN void sun_delete_partition(int i);
684 STATIC_SUN void sun_change_sysid(int i, int sys);
685 STATIC_SUN void sun_list_table(int xtra);
686 STATIC_SUN void add_sun_partition(int n, int sys);
687 #if ENABLE_FEATURE_FDISK_ADVANCED
688 STATIC_SUN void sun_set_alt_cyl(void);
689 STATIC_SUN void sun_set_ncyl(int cyl);
690 STATIC_SUN void sun_set_xcyl(void);
691 STATIC_SUN void sun_set_ilfact(void);
692 STATIC_SUN void sun_set_rspeed(void);
693 STATIC_SUN void sun_set_pcylcount(void);
695 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
696 STATIC_SUN void verify_sun(void);
697 STATIC_SUN void sun_write_table(void);
698 #include "fdisk_sun.c"
701 static inline_if_little_endian unsigned
702 read4_little_endian(const unsigned char *cp)
705 move_from_unaligned32(v, cp);
710 get_start_sect(const struct partition *p)
712 return read4_little_endian(p->start4);
716 get_nr_sects(const struct partition *p)
718 return read4_little_endian(p->size4);
721 #if ENABLE_FEATURE_FDISK_WRITABLE
722 /* start_sect and nr_sects are stored little endian on all machines */
723 /* moreover, they are not aligned correctly */
724 static inline_if_little_endian void
725 store4_little_endian(unsigned char *cp, unsigned val)
727 uint32_t v = SWAP_LE32(val);
728 move_to_unaligned32(cp, v);
732 set_start_sect(struct partition *p, unsigned start_sect)
734 store4_little_endian(p->start4, start_sect);
738 set_nr_sects(struct partition *p, unsigned nr_sects)
740 store4_little_endian(p->size4, nr_sects);
744 /* Allocate a buffer and read a partition table sector */
746 read_pte(struct pte *pe, sector_t offset)
748 pe->offset_from_dev_start = offset;
749 pe->sectorbuffer = xzalloc(sector_size);
751 /* xread would make us abort - bad for fdisk -l */
752 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
753 fdisk_fatal(unable_to_read);
754 #if ENABLE_FEATURE_FDISK_WRITABLE
757 pe->part_table = pe->ext_pointer = NULL;
761 get_partition_start_from_dev_start(const struct pte *pe)
763 return pe->offset_from_dev_start + get_start_sect(pe->part_table);
766 #if ENABLE_FEATURE_FDISK_WRITABLE
768 * Avoid warning about DOS partitions when no DOS partition was changed.
769 * Here a heuristic "is probably dos partition".
770 * We might also do the opposite and warn in all cases except
771 * for "is probably nondos partition".
775 is_dos_partition(int t)
777 return (t == 1 || t == 4 || t == 6 ||
778 t == 0x0b || t == 0x0c || t == 0x0e ||
779 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
780 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
781 t == 0xc1 || t == 0xc4 || t == 0xc6);
788 puts("Command Action");
790 puts("a\ttoggle a read only flag"); /* sun */
791 puts("b\tedit bsd disklabel");
792 puts("c\ttoggle the mountable flag"); /* sun */
793 puts("d\tdelete a partition");
794 puts("l\tlist known partition types");
795 puts("n\tadd a new partition");
796 puts("o\tcreate a new empty DOS partition table");
797 puts("p\tprint the partition table");
798 puts("q\tquit without saving changes");
799 puts("s\tcreate a new empty Sun disklabel"); /* sun */
800 puts("t\tchange a partition's system id");
801 puts("u\tchange display/entry units");
802 puts("v\tverify the partition table");
803 puts("w\twrite table to disk and exit");
804 #if ENABLE_FEATURE_FDISK_ADVANCED
805 puts("x\textra functionality (experts only)");
807 } else if (LABEL_IS_SGI) {
808 puts("a\tselect bootable partition"); /* sgi flavour */
809 puts("b\tedit bootfile entry"); /* sgi */
810 puts("c\tselect sgi swap partition"); /* sgi flavour */
811 puts("d\tdelete a partition");
812 puts("l\tlist known partition types");
813 puts("n\tadd a new partition");
814 puts("o\tcreate a new empty DOS partition table");
815 puts("p\tprint the partition table");
816 puts("q\tquit without saving changes");
817 puts("s\tcreate a new empty Sun disklabel"); /* sun */
818 puts("t\tchange a partition's system id");
819 puts("u\tchange display/entry units");
820 puts("v\tverify the partition table");
821 puts("w\twrite table to disk and exit");
822 } else if (LABEL_IS_AIX) {
823 puts("o\tcreate a new empty DOS partition table");
824 puts("q\tquit without saving changes");
825 puts("s\tcreate a new empty Sun disklabel"); /* sun */
826 } else if (LABEL_IS_GPT) {
827 puts("o\tcreate a new empty DOS partition table");
828 puts("p\tprint the partition table");
829 puts("q\tquit without saving changes");
830 puts("s\tcreate a new empty Sun disklabel"); /* sun */
832 puts("a\ttoggle a bootable flag");
833 puts("b\tedit bsd disklabel");
834 puts("c\ttoggle the dos compatibility flag");
835 puts("d\tdelete a partition");
836 puts("l\tlist known partition types");
837 puts("n\tadd a new partition");
838 puts("o\tcreate a new empty DOS partition table");
839 puts("p\tprint the partition table");
840 puts("q\tquit without saving changes");
841 puts("s\tcreate a new empty Sun disklabel"); /* sun */
842 puts("t\tchange a partition's system id");
843 puts("u\tchange display/entry units");
844 puts("v\tverify the partition table");
845 puts("w\twrite table to disk and exit");
846 #if ENABLE_FEATURE_FDISK_ADVANCED
847 puts("x\textra functionality (experts only)");
851 #endif /* FEATURE_FDISK_WRITABLE */
854 #if ENABLE_FEATURE_FDISK_ADVANCED
858 puts("Command Action");
860 puts("a\tchange number of alternate cylinders"); /*sun*/
861 puts("c\tchange number of cylinders");
862 puts("d\tprint the raw data in the partition table");
863 puts("e\tchange number of extra sectors per cylinder");/*sun*/
864 puts("h\tchange number of heads");
865 puts("i\tchange interleave factor"); /*sun*/
866 puts("o\tchange rotation speed (rpm)"); /*sun*/
867 puts("p\tprint the partition table");
868 puts("q\tquit without saving changes");
869 puts("r\treturn to main menu");
870 puts("s\tchange number of sectors/track");
871 puts("v\tverify the partition table");
872 puts("w\twrite table to disk and exit");
873 puts("y\tchange number of physical cylinders"); /*sun*/
874 } else if (LABEL_IS_SGI) {
875 puts("b\tmove beginning of data in a partition"); /* !sun */
876 puts("c\tchange number of cylinders");
877 puts("d\tprint the raw data in the partition table");
878 puts("e\tlist extended partitions"); /* !sun */
879 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
880 puts("h\tchange number of heads");
881 puts("p\tprint the partition table");
882 puts("q\tquit without saving changes");
883 puts("r\treturn to main menu");
884 puts("s\tchange number of sectors/track");
885 puts("v\tverify the partition table");
886 puts("w\twrite table to disk and exit");
887 } else if (LABEL_IS_AIX) {
888 puts("b\tmove beginning of data in a partition"); /* !sun */
889 puts("c\tchange number of cylinders");
890 puts("d\tprint the raw data in the partition table");
891 puts("e\tlist extended partitions"); /* !sun */
892 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
893 puts("h\tchange number of heads");
894 puts("p\tprint the partition table");
895 puts("q\tquit without saving changes");
896 puts("r\treturn to main menu");
897 puts("s\tchange number of sectors/track");
898 puts("v\tverify the partition table");
899 puts("w\twrite table to disk and exit");
901 puts("b\tmove beginning of data in a partition"); /* !sun */
902 puts("c\tchange number of cylinders");
903 puts("d\tprint the raw data in the partition table");
904 puts("e\tlist extended partitions"); /* !sun */
905 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
906 #if ENABLE_FEATURE_SGI_LABEL
907 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
909 puts("h\tchange number of heads");
910 puts("p\tprint the partition table");
911 puts("q\tquit without saving changes");
912 puts("r\treturn to main menu");
913 puts("s\tchange number of sectors/track");
914 puts("v\tverify the partition table");
915 puts("w\twrite table to disk and exit");
918 #endif /* ADVANCED mode */
920 #if ENABLE_FEATURE_FDISK_WRITABLE
921 static const char *const *
925 LABEL_IS_SUN ? sun_sys_types :
926 LABEL_IS_SGI ? sgi_sys_types :
930 #define get_sys_types() i386_sys_types
934 partition_type(unsigned char type)
937 const char *const *types = get_sys_types();
939 for (i = 0; types[i]; i++)
940 if ((unsigned char)types[i][0] == type)
947 is_cleared_partition(const struct partition *p)
949 /* We consider partition "cleared" only if it has only zeros */
950 const char *cp = (const char *)p;
951 int cnt = sizeof(*p);
959 clear_partition(struct partition *p)
962 memset(p, 0, sizeof(*p));
965 #if ENABLE_FEATURE_FDISK_WRITABLE
969 return LABEL_IS_SUN ? sunlabel->infos[i].id :
970 (LABEL_IS_SGI ? sgi_get_sysid(i) :
971 ptes[i].part_table->sys_ind);
975 list_types(const char *const *sys)
980 unsigned done, next, size;
983 for (size = 0; sys[size]; size++)
987 for (i = COLS-1; i >= 0; i--) {
988 done += (size + i - done) / (i + 1);
989 last[COLS-1 - i] = done;
994 printf("%c%2x %-22.22s", i ? ' ' : '\n',
995 (unsigned char)sys[next][0],
997 next = last[i++] + done;
998 if (i >= COLS || next >= last[i]) {
1002 } while (done < last[0]);
1006 #define set_hsc(h, s, c, sector) do \
1008 s = sector % g_sectors + 1; \
1009 sector /= g_sectors; \
1010 h = sector % g_heads; \
1011 sector /= g_heads; \
1012 c = sector & 0xff; \
1013 s |= (sector >> 2) & 0xc0; \
1016 static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop)
1018 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1019 start = g_heads * g_sectors * 1024 - 1;
1020 set_hsc(p->head, p->sector, p->cyl, start);
1022 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1023 stop = g_heads * g_sectors * 1024 - 1;
1024 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1028 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1030 struct partition *p;
1034 p = ptes[i].ext_pointer;
1035 offset = extended_offset;
1037 p = ptes[i].part_table;
1038 offset = ptes[i].offset_from_dev_start;
1042 set_start_sect(p, start - offset);
1043 set_nr_sects(p, stop - start + 1);
1044 set_hsc_start_end(p, start, stop);
1045 ptes[i].changed = 1;
1052 if (g_heads && g_sectors && g_cylinders)
1055 printf("Unknown value(s) for:");
1061 printf(" cylinders");
1062 #if ENABLE_FEATURE_FDISK_WRITABLE
1063 puts(" (settable in the extra functions menu)");
1073 int cyl_units = g_heads * g_sectors;
1075 if (display_in_cyl_units && cyl_units)
1076 units_per_sector = cyl_units;
1078 units_per_sector = 1; /* in sectors */
1081 #if ENABLE_FEATURE_FDISK_WRITABLE
1083 warn_cylinders(void)
1085 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1087 "The number of cylinders for this disk is set to %u.\n"
1088 "There is nothing wrong with that, but this is larger than 1024,\n"
1089 "and could in certain setups cause problems with:\n"
1090 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1091 "2) booting and partitioning software from other OSs\n"
1092 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1098 read_extended(int ext)
1102 struct partition *p, *q;
1106 pex->ext_pointer = pex->part_table;
1108 p = pex->part_table;
1109 if (!get_start_sect(p)) {
1110 puts("Bad offset in primary extended partition");
1114 while (IS_EXTENDED(p->sys_ind)) {
1115 struct pte *pe = &ptes[g_partitions];
1117 if (g_partitions >= MAXIMUM_PARTS) {
1118 /* This is not a Linux restriction, but
1119 this program uses arrays of size MAXIMUM_PARTS.
1120 Do not try to 'improve' this test. */
1121 struct pte *pre = &ptes[g_partitions - 1];
1122 #if ENABLE_FEATURE_FDISK_WRITABLE
1123 printf("Warning: deleting partitions after %u\n",
1127 clear_partition(pre->ext_pointer);
1131 read_pte(pe, extended_offset + get_start_sect(p));
1133 if (!extended_offset)
1134 extended_offset = get_start_sect(p);
1136 q = p = pt_offset(pe->sectorbuffer, 0);
1137 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1138 if (IS_EXTENDED(p->sys_ind)) {
1139 if (pe->ext_pointer)
1140 printf("Warning: extra link "
1141 "pointer in partition table"
1142 " %u\n", g_partitions + 1);
1144 pe->ext_pointer = p;
1145 } else if (p->sys_ind) {
1147 printf("Warning: ignoring extra "
1148 "data in partition table"
1149 " %u\n", g_partitions + 1);
1155 /* very strange code here... */
1156 if (!pe->part_table) {
1157 if (q != pe->ext_pointer)
1160 pe->part_table = q + 1;
1162 if (!pe->ext_pointer) {
1163 if (q != pe->part_table)
1164 pe->ext_pointer = q;
1166 pe->ext_pointer = q + 1;
1169 p = pe->ext_pointer;
1173 #if ENABLE_FEATURE_FDISK_WRITABLE
1174 /* remove empty links */
1176 for (i = 4; i < g_partitions; i++) {
1177 struct pte *pe = &ptes[i];
1179 if (!get_nr_sects(pe->part_table)
1180 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1182 printf("Omitting empty partition (%u)\n", i+1);
1183 delete_partition(i);
1184 goto remove; /* numbering changed */
1190 #if ENABLE_FEATURE_FDISK_WRITABLE
1192 create_doslabel(void)
1194 printf(msg_building_new_label, "DOS disklabel");
1196 current_label_type = LABEL_DOS;
1197 #if ENABLE_FEATURE_OSF_LABEL
1198 possibly_osf_label = 0;
1202 memset(&MBRbuffer[510 - 4*16], 0, 4*16);
1203 write_part_table_flag(MBRbuffer);
1204 extended_offset = 0;
1205 set_all_unchanged();
1207 get_boot(CREATE_EMPTY_DOS);
1212 get_sectorsize(void)
1214 if (!user_set_sector_size) {
1216 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1218 if (sector_size != DEFAULT_SECTOR_SIZE)
1219 printf("Note: sector size is %u "
1220 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1226 get_kernel_geometry(void)
1228 struct hd_geometry geometry;
1230 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1231 kern_heads = geometry.heads;
1232 kern_sectors = geometry.sectors;
1233 /* never use geometry.cylinders - it is truncated */
1238 get_partition_table_geometry(void)
1240 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1241 struct partition *p;
1242 int i, h, s, hh, ss;
1246 if (!(valid_part_table_flag((char*)bufp)))
1250 for (i = 0; i < 4; i++) {
1251 p = pt_offset(bufp, i);
1252 if (p->sys_ind != 0) {
1253 h = p->end_head + 1;
1254 s = (p->end_sector & 077);
1259 } else if (hh != h || ss != s)
1264 if (!first && !bad) {
1276 sec_fac = sector_size / 512;
1277 #if ENABLE_FEATURE_SUN_LABEL
1278 guess_device_type();
1280 g_heads = g_cylinders = g_sectors = 0;
1281 kern_heads = kern_sectors = 0;
1282 pt_heads = pt_sectors = 0;
1284 get_kernel_geometry();
1285 get_partition_table_geometry();
1287 g_heads = user_heads ? user_heads :
1288 pt_heads ? pt_heads :
1289 kern_heads ? kern_heads : 255;
1290 g_sectors = user_sectors ? user_sectors :
1291 pt_sectors ? pt_sectors :
1292 kern_sectors ? kern_sectors : 63;
1293 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1296 if (dos_compatible_flag)
1297 sector_offset = g_sectors;
1299 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1301 g_cylinders = user_cylinders;
1305 * Opens disk_device and optionally reads MBR.
1306 * If what == OPEN_MAIN:
1307 * Open device, read MBR. Abort program on short read. Create empty
1308 * disklabel if the on-disk structure is invalid (WRITABLE mode).
1309 * If what == TRY_ONLY:
1310 * Open device, read MBR. Return an error if anything is out of place.
1311 * Do not create an empty disklabel. This is used for the "list"
1312 * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
1313 * If what == CREATE_EMPTY_*:
1314 * This means that get_boot() was called recursively from create_*label().
1315 * Do not re-open the device; just set up the ptes array and print
1316 * geometry warnings.
1319 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1320 * 0: found or created label
1323 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1324 static int get_boot(enum action what)
1326 static int get_boot(void)
1327 #define get_boot(what) get_boot()
1333 for (i = 0; i < 4; i++) {
1334 struct pte *pe = &ptes[i];
1335 pe->part_table = pt_offset(MBRbuffer, i);
1336 pe->ext_pointer = NULL;
1337 pe->offset_from_dev_start = 0;
1338 pe->sectorbuffer = MBRbuffer;
1339 #if ENABLE_FEATURE_FDISK_WRITABLE
1340 pe->changed = (what == CREATE_EMPTY_DOS);
1344 #if ENABLE_FEATURE_FDISK_WRITABLE
1345 // ALERT! highly idiotic design!
1346 // We end up here when we call get_boot() recursively
1347 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1348 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1349 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1350 // So skip opening device _again_...
1351 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1354 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1357 fd = open(disk_device, O_RDONLY);
1359 if (what == TRY_ONLY)
1361 fdisk_fatal(unable_to_open);
1363 printf("'%s' is opened for read only\n", disk_device);
1365 xmove_fd(fd, dev_fd);
1366 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1367 if (what == TRY_ONLY) {
1371 fdisk_fatal(unable_to_read);
1374 fd = open(disk_device, O_RDONLY);
1377 if (512 != full_read(fd, MBRbuffer, 512)) {
1381 xmove_fd(fd, dev_fd);
1387 #if ENABLE_FEATURE_SUN_LABEL
1388 if (check_sun_label())
1391 #if ENABLE_FEATURE_SGI_LABEL
1392 if (check_sgi_label())
1395 #if ENABLE_FEATURE_AIX_LABEL
1396 if (check_aix_label())
1399 #if ENABLE_FEATURE_GPT_LABEL
1400 if (check_gpt_label())
1403 #if ENABLE_FEATURE_OSF_LABEL
1404 if (check_osf_label()) {
1405 possibly_osf_label = 1;
1406 if (!valid_part_table_flag(MBRbuffer)) {
1407 current_label_type = LABEL_OSF;
1410 puts("This disk has both DOS and BSD magic.\n"
1411 "Give the 'b' command to go to BSD mode.");
1415 #if !ENABLE_FEATURE_FDISK_WRITABLE
1416 if (!valid_part_table_flag(MBRbuffer))
1419 if (!valid_part_table_flag(MBRbuffer)) {
1420 if (what == OPEN_MAIN) {
1421 puts("Device contains neither a valid DOS "
1422 "partition table, nor Sun, SGI, OSF or GPT "
1425 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1435 #endif /* FEATURE_FDISK_WRITABLE */
1438 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1441 for (i = 0; i < 4; i++) {
1442 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1443 if (g_partitions != 4)
1444 printf("Ignoring extra extended "
1445 "partition %u\n", i + 1);
1451 for (i = 3; i < g_partitions; i++) {
1452 struct pte *pe = &ptes[i];
1453 if (!valid_part_table_flag(pe->sectorbuffer)) {
1454 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1455 "table %u will be corrected by w(rite)\n",
1456 pe->sectorbuffer[510],
1457 pe->sectorbuffer[511],
1459 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1466 #if ENABLE_FEATURE_FDISK_WRITABLE
1468 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1469 * If the user hits Enter, DFLT is returned.
1470 * Answers like +10 are interpreted as offsets from BASE.
1472 * There is no default if DFLT is not between LOW and HIGH.
1475 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1479 const char *fmt = "%s (%u-%u, default %u): ";
1481 if (dflt < low || dflt > high) {
1482 fmt = "%s (%u-%u): ";
1487 int use_default = default_ok;
1489 /* ask question and read answer */
1491 printf(fmt, mesg, low, high, dflt);
1492 read_maybe_empty("");
1493 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1494 && *line_ptr != '-' && *line_ptr != '+');
1496 if (*line_ptr == '+' || *line_ptr == '-') {
1497 int minus = (*line_ptr == '-');
1500 value = atoi(line_ptr + 1);
1502 /* (1) if 2nd char is digit, use_default = 0.
1503 * (2) move line_ptr to first non-digit. */
1504 while (isdigit(*++line_ptr))
1507 switch (*line_ptr) {
1510 if (!display_in_cyl_units)
1511 value *= g_heads * g_sectors;
1525 absolute = 1000000000;
1534 bytes = (ullong) value * absolute;
1535 unit = sector_size * units_per_sector;
1536 bytes += unit/2; /* round */
1544 value = atoi(line_ptr);
1545 while (isdigit(*line_ptr)) {
1552 printf("Using default value %u\n", value);
1554 if (value >= low && value <= high)
1556 puts("Value is out of range");
1562 get_partition(int warn, unsigned max)
1567 i = read_int(1, 0, max, 0, "Partition number") - 1;
1571 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1572 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1573 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1575 printf("Warning: partition %u has empty type\n", i+1);
1582 get_existing_partition(int warn, unsigned max)
1587 for (i = 0; i < max; i++) {
1588 struct pte *pe = &ptes[i];
1589 struct partition *p = pe->part_table;
1591 if (p && !is_cleared_partition(p)) {
1598 printf("Selected partition %u\n", pno+1);
1601 puts("No partition is defined yet!");
1605 return get_partition(warn, max);
1609 get_nonexisting_partition(int warn, unsigned max)
1614 for (i = 0; i < max; i++) {
1615 struct pte *pe = &ptes[i];
1616 struct partition *p = pe->part_table;
1618 if (p && is_cleared_partition(p)) {
1625 printf("Selected partition %u\n", pno+1);
1628 puts("All primary partitions have been defined already!");
1632 return get_partition(warn, max);
1639 display_in_cyl_units = !display_in_cyl_units;
1641 printf("Changing display/entry units to %s\n",
1646 toggle_active(int i)
1648 struct pte *pe = &ptes[i];
1649 struct partition *p = pe->part_table;
1651 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1652 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1653 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1658 toggle_dos_compatibility_flag(void)
1660 dos_compatible_flag = 1 - dos_compatible_flag;
1661 if (dos_compatible_flag) {
1662 sector_offset = g_sectors;
1663 printf("DOS Compatibility flag is %sset\n", "");
1666 printf("DOS Compatibility flag is %sset\n", "not ");
1671 delete_partition(int i)
1673 struct pte *pe = &ptes[i];
1674 struct partition *p = pe->part_table;
1675 struct partition *q = pe->ext_pointer;
1677 /* Note that for the fifth partition (i == 4) we don't actually
1678 * decrement partitions.
1681 if (warn_geometry())
1682 return; /* C/H/S not set */
1686 sun_delete_partition(i);
1690 sgi_delete_partition(i);
1695 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1697 ptes[ext_index].ext_pointer = NULL;
1698 extended_offset = 0;
1704 if (!q->sys_ind && i > 4) {
1705 /* the last one in the chain - just delete */
1708 clear_partition(ptes[i].ext_pointer);
1709 ptes[i].changed = 1;
1711 /* not the last one - further ones will be moved down */
1713 /* delete this link in the chain */
1714 p = ptes[i-1].ext_pointer;
1716 set_start_sect(p, get_start_sect(q));
1717 set_nr_sects(p, get_nr_sects(q));
1718 ptes[i-1].changed = 1;
1719 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1720 /* the first logical in a longer chain */
1723 if (pe->part_table) /* prevent SEGFAULT */
1724 set_start_sect(pe->part_table,
1725 get_partition_start_from_dev_start(pe) -
1727 pe->offset_from_dev_start = extended_offset;
1731 if (g_partitions > 5) {
1733 while (i < g_partitions) {
1734 ptes[i] = ptes[i+1];
1738 /* the only logical: clear only */
1739 clear_partition(ptes[i].part_table);
1747 int i, sys, origsys;
1748 struct partition *p;
1750 /* If sgi_label then don't use get_existing_partition,
1751 let the user select a partition, since get_existing_partition()
1752 only works for Linux like partition tables. */
1753 if (!LABEL_IS_SGI) {
1754 i = get_existing_partition(0, g_partitions);
1756 i = get_partition(0, g_partitions);
1760 p = ptes[i].part_table;
1761 origsys = sys = get_sysid(i);
1763 /* if changing types T to 0 is allowed, then
1764 the reverse change must be allowed, too */
1765 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1766 printf("Partition %u does not exist yet!\n", i + 1);
1770 sys = read_hex(get_sys_types());
1772 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1773 puts("Type 0 means free space to many systems\n"
1774 "(but not to Linux). Having partitions of\n"
1775 "type 0 is probably unwise.");
1779 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1780 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1781 puts("You cannot change a partition into"
1782 " an extended one or vice versa");
1788 #if ENABLE_FEATURE_SUN_LABEL
1789 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1790 puts("Consider leaving partition 3 "
1791 "as Whole disk (5),\n"
1792 "as SunOS/Solaris expects it and "
1793 "even Linux likes it\n");
1795 #if ENABLE_FEATURE_SGI_LABEL
1798 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1799 (i == 8 && sys != 0)
1802 puts("Consider leaving partition 9 "
1803 "as volume header (0),\nand "
1804 "partition 11 as entire volume (6)"
1805 "as IRIX expects it\n");
1811 sun_change_sysid(i, sys);
1812 } else if (LABEL_IS_SGI) {
1813 sgi_change_sysid(i, sys);
1817 printf("Changed system type of partition %u "
1818 "to %x (%s)\n", i + 1, sys,
1819 partition_type(sys));
1820 ptes[i].changed = 1;
1821 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1827 #endif /* FEATURE_FDISK_WRITABLE */
1830 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1831 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1832 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1833 * Lubkin Oct. 1991). */
1836 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1838 int spc = g_heads * g_sectors;
1842 *h = ls / g_sectors;
1843 *s = ls % g_sectors + 1; /* sectors count from 1 */
1847 check_consistency(const struct partition *p, int partition)
1849 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1850 unsigned pec, peh, pes; /* physical ending c, h, s */
1851 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1852 unsigned lec, leh, les; /* logical ending c, h, s */
1854 if (!g_heads || !g_sectors || (partition >= 4))
1855 return; /* do not check extended partitions */
1857 /* physical beginning c, h, s */
1858 pbc = cylinder(p->sector, p->cyl);
1860 pbs = sector(p->sector);
1862 /* physical ending c, h, s */
1863 pec = cylinder(p->end_sector, p->end_cyl);
1865 pes = sector(p->end_sector);
1867 /* compute logical beginning (c, h, s) */
1868 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1870 /* compute logical ending (c, h, s) */
1871 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1873 /* Same physical / logical beginning? */
1874 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1875 printf("Partition %u has different physical/logical "
1876 "start (non-Linux?):\n", partition + 1);
1877 printf(" phys=(%u,%u,%u) ", pbc, pbh, pbs);
1878 printf("logical=(%u,%u,%u)\n", lbc, lbh, lbs);
1881 /* Same physical / logical ending? */
1882 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1883 printf("Partition %u has different physical/logical "
1884 "end:\n", partition + 1);
1885 printf(" phys=(%u,%u,%u) ", pec, peh, pes);
1886 printf("logical=(%u,%u,%u)\n", lec, leh, les);
1889 /* Ending on cylinder boundary? */
1890 if (peh != (g_heads - 1) || pes != g_sectors) {
1891 printf("Partition %u does not end on cylinder boundary\n",
1897 list_disk_geometry(void)
1899 ullong bytes = ((ullong)total_number_of_sectors << 9);
1900 ullong xbytes = bytes / (1024*1024);
1903 if (xbytes >= 10000) {
1904 xbytes += 512; /* fdisk util-linux 2.28 does this */
1908 printf("Disk %s: %llu %cB, %llu bytes, %"SECT_FMT"u sectors\n"
1909 "%u cylinders, %u heads, %u sectors/track\n"
1910 "Units: %s of %u * %u = %u bytes\n\n",
1911 disk_device, xbytes, x,
1912 bytes, total_number_of_sectors,
1913 g_cylinders, g_heads, g_sectors,
1915 units_per_sector, sector_size, units_per_sector * sector_size
1920 * Check whether partition entries are ordered by their starting positions.
1921 * Return 0 if OK. Return i if partition i should have been earlier.
1922 * Two separate checks: primary and logical partitions.
1925 wrong_p_order(int *prev)
1927 const struct pte *pe;
1928 const struct partition *p;
1929 sector_t last_p_start_pos = 0, p_start_pos;
1930 unsigned i, last_i = 0;
1932 for (i = 0; i < g_partitions; i++) {
1935 last_p_start_pos = 0;
1940 p_start_pos = get_partition_start_from_dev_start(pe);
1942 if (last_p_start_pos > p_start_pos) {
1948 last_p_start_pos = p_start_pos;
1955 #if ENABLE_FEATURE_FDISK_ADVANCED
1957 * Fix the chain of logicals.
1958 * extended_offset is unchanged, the set of sectors used is unchanged
1959 * The chain is sorted so that sectors increase, and so that
1960 * starting sectors increase.
1962 * After this it may still be that cfdisk doesnt like the table.
1963 * (This is because cfdisk considers expanded parts, from link to
1964 * end of partition, and these may still overlap.)
1966 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1970 fix_chain_of_logicals(void)
1972 int j, oj, ojj, sj, sjj;
1973 struct partition *pj,*pjj,tmp;
1975 /* Stage 1: sort sectors but leave sector of part 4 */
1976 /* (Its sector is the global extended_offset.) */
1978 for (j = 5; j < g_partitions - 1; j++) {
1979 oj = ptes[j].offset_from_dev_start;
1980 ojj = ptes[j+1].offset_from_dev_start;
1982 ptes[j].offset_from_dev_start = ojj;
1983 ptes[j+1].offset_from_dev_start = oj;
1984 pj = ptes[j].part_table;
1985 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1986 pjj = ptes[j+1].part_table;
1987 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1988 set_start_sect(ptes[j-1].ext_pointer,
1989 ojj-extended_offset);
1990 set_start_sect(ptes[j].ext_pointer,
1991 oj-extended_offset);
1996 /* Stage 2: sort starting sectors */
1998 for (j = 4; j < g_partitions - 1; j++) {
1999 pj = ptes[j].part_table;
2000 pjj = ptes[j+1].part_table;
2001 sj = get_start_sect(pj);
2002 sjj = get_start_sect(pjj);
2003 oj = ptes[j].offset_from_dev_start;
2004 ojj = ptes[j+1].offset_from_dev_start;
2005 if (oj+sj > ojj+sjj) {
2009 set_start_sect(pj, ojj+sjj-oj);
2010 set_start_sect(pjj, oj+sj-ojj);
2015 /* Probably something was changed */
2016 for (j = 4; j < g_partitions; j++)
2017 ptes[j].changed = 1;
2022 fix_partition_table_order(void)
2024 struct pte *pei, *pek;
2027 if (!wrong_p_order(NULL)) {
2028 puts("Ordering is already correct\n");
2032 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2033 /* partition i should have come earlier, move it */
2034 /* We have to move data in the MBR */
2035 struct partition *pi, *pk, *pe, pbuf;
2039 pe = pei->ext_pointer;
2040 pei->ext_pointer = pek->ext_pointer;
2041 pek->ext_pointer = pe;
2043 pi = pei->part_table;
2044 pk = pek->part_table;
2046 memmove(&pbuf, pi, sizeof(struct partition));
2047 memmove(pi, pk, sizeof(struct partition));
2048 memmove(pk, &pbuf, sizeof(struct partition));
2050 pei->changed = pek->changed = 1;
2054 fix_chain_of_logicals();
2060 /* Return partition name */
2062 partname(const char *dev, int pno, int lth)
2069 bufp = auto_string(xzalloc(80));
2075 if (isdigit(dev[w-1]))
2078 /* devfs kludge - note: fdisk partition names are not supposed
2079 to equal kernel names, so there is no reason to do this */
2080 if (strcmp(dev + w - 4, "disc") == 0) {
2088 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
2089 lth-wp-2, w, dev, p, pno);
2091 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
2097 chs_string11(unsigned cyl, unsigned head, unsigned sect)
2099 char *buf = auto_string(xzalloc(sizeof(int)*3 * 3));
2100 sprintf(buf, "%u,%u,%u", cylinder(sect,cyl), head, sector(sect));
2105 list_table(int xtra)
2110 sun_list_table(xtra);
2114 sgi_list_table(xtra);
2118 gpt_list_table(xtra);
2122 list_disk_geometry();
2125 xbsd_print_disklabel(xtra);
2129 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2130 * but if the device name ends in a digit, say /dev/foo1,
2131 * then the partition is called /dev/foo1p3.
2133 w = strlen(disk_device);
2134 if (w && isdigit(disk_device[w-1]))
2139 printf("%-*s Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type\n",
2142 for (i = 0; i < g_partitions; i++) {
2143 const struct partition *p;
2144 const struct pte *pe = &ptes[i];
2147 sector_t start_sect;
2152 if (!p || is_cleared_partition(p))
2155 sprintf(boot4, "%02x", p->boot_ind);
2156 if ((p->boot_ind & 0x7f) == 0) {
2157 /* 0x80 shown as '*', 0x00 is ' ' */
2158 boot4[0] = p->boot_ind ? '*' : ' ';
2162 start_sect = get_partition_start_from_dev_start(pe);
2163 end_sect = start_sect;
2164 nr_sects = get_nr_sects(p);
2166 end_sect += nr_sects - 1;
2168 smart_ulltoa5((ullong)nr_sects * sector_size,
2169 numstr6, " KMGTPEZY")[0] = '\0';
2171 #define SFMT SECT_FMT
2172 // Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
2173 printf("%s%s %-11s"/**/" %-11s"/**/" %10"SFMT"u %10"SFMT"u %10"SFMT"u %s %2x %s\n",
2174 partname(disk_device, i+1, w+2),
2176 chs_string11(p->cyl, p->head, p->sector),
2177 chs_string11(p->end_cyl, p->end_head, p->end_sector),
2183 partition_type(p->sys_ind)
2186 check_consistency(p, i);
2189 /* Is partition table in disk order? It need not be, but... */
2190 /* partition table entries are not checked for correct order
2191 * if this is a sgi, sun or aix labeled disk... */
2192 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2194 puts("\nPartition table entries are not in disk order");
2198 #if ENABLE_FEATURE_FDISK_ADVANCED
2200 x_list_table(int extend)
2202 const struct pte *pe;
2203 const struct partition *p;
2206 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2207 disk_device, g_heads, g_sectors, g_cylinders);
2208 puts("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID");
2209 for (i = 0; i < g_partitions; i++) {
2211 p = (extend ? pe->ext_pointer : pe->part_table);
2213 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2217 cylinder(p->sector, p->cyl),
2219 sector(p->end_sector),
2220 cylinder(p->end_sector, p->end_cyl),
2226 check_consistency(p, i);
2232 #if ENABLE_FEATURE_FDISK_WRITABLE
2234 fill_bounds(sector_t *first, sector_t *last)
2237 const struct pte *pe = &ptes[0];
2238 const struct partition *p;
2240 for (i = 0; i < g_partitions; pe++,i++) {
2242 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2243 first[i] = 0xffffffff;
2246 first[i] = get_partition_start_from_dev_start(pe);
2247 last[i] = first[i] + get_nr_sects(p) - 1;
2253 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2255 sector_t total, real_s, real_c;
2257 real_s = sector(s) - 1;
2258 real_c = cylinder(s, c);
2259 total = (real_c * g_sectors + real_s) * g_heads + h;
2261 printf("Partition %u contains sector 0\n", n);
2263 printf("Partition %u: head %u greater than maximum %u\n",
2265 if (real_s >= g_sectors)
2266 printf("Partition %u: sector %u greater than "
2267 "maximum %u\n", n, s, g_sectors);
2268 if (real_c >= g_cylinders)
2269 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2270 "maximum %u\n", n, real_c + 1, g_cylinders);
2271 if (g_cylinders <= 1024 && start != total)
2272 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2273 "total %"SECT_FMT"u\n", n, start, total);
2282 sector_t first[g_partitions], last[g_partitions];
2283 struct partition *p;
2285 if (warn_geometry())
2297 fill_bounds(first, last);
2298 for (i = 0; i < g_partitions; i++) {
2299 struct pte *pe = &ptes[i];
2302 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2303 check_consistency(p, i);
2304 if (get_partition_start_from_dev_start(pe) < first[i])
2305 printf("Warning: bad start-of-data in "
2306 "partition %u\n", i + 1);
2307 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2309 total += last[i] + 1 - first[i];
2310 for (j = 0; j < i; j++) {
2311 if ((first[i] >= first[j] && first[i] <= last[j])
2312 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2313 printf("Warning: partition %u overlaps "
2314 "partition %u\n", j + 1, i + 1);
2315 total += first[i] >= first[j] ?
2316 first[i] : first[j];
2317 total -= last[i] <= last[j] ?
2324 if (extended_offset) {
2325 struct pte *pex = &ptes[ext_index];
2326 sector_t e_last = get_start_sect(pex->part_table) +
2327 get_nr_sects(pex->part_table) - 1;
2329 for (i = 4; i < g_partitions; i++) {
2331 p = ptes[i].part_table;
2333 if (i != 4 || i + 1 < g_partitions)
2334 printf("Warning: partition %u "
2335 "is empty\n", i + 1);
2336 } else if (first[i] < extended_offset || last[i] > e_last) {
2337 printf("Logical partition %u not entirely in "
2338 "partition %u\n", i + 1, ext_index + 1);
2343 chs_size = (sector_t)g_heads * g_sectors * g_cylinders;
2344 if (total > chs_size)
2345 printf("Total allocated sectors %u"
2346 " greater than CHS size %"SECT_FMT"u\n",
2350 total = chs_size - total;
2352 printf("%"SECT_FMT"u unallocated sectors\n", total);
2357 add_partition(int n, int sys)
2359 char mesg[256]; /* 48 does not suffice in Japanese */
2360 int i, num_read = 0;
2361 struct partition *p = ptes[n].part_table;
2362 struct partition *q = ptes[ext_index].part_table;
2363 sector_t limit, temp;
2364 sector_t start, stop = 0;
2365 sector_t first[g_partitions], last[g_partitions];
2367 if (p && p->sys_ind) {
2368 printf(msg_part_already_defined, n + 1);
2371 fill_bounds(first, last);
2373 start = sector_offset;
2374 if (display_in_cyl_units || !total_number_of_sectors)
2375 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2377 limit = total_number_of_sectors - 1;
2378 if (extended_offset) {
2379 first[ext_index] = extended_offset;
2380 last[ext_index] = get_start_sect(q) +
2381 get_nr_sects(q) - 1;
2384 start = extended_offset + sector_offset;
2385 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2387 if (display_in_cyl_units)
2388 for (i = 0; i < g_partitions; i++)
2389 first[i] = (cround(first[i]) - 1) * units_per_sector;
2391 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2394 for (i = 0; i < g_partitions; i++) {
2397 if (start == ptes[i].offset_from_dev_start)
2398 start += sector_offset;
2399 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2400 if (start >= first[i] && start <= lastplusoff)
2401 start = lastplusoff + 1;
2405 if (start >= temp+units_per_sector && num_read) {
2406 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2410 if (!num_read && start == temp) {
2411 sector_t saved_start;
2413 saved_start = start;
2414 start = read_int(cround(saved_start), cround(saved_start), cround(limit), 0, mesg);
2415 if (display_in_cyl_units) {
2416 start = (start - 1) * units_per_sector;
2417 if (start < saved_start)
2418 start = saved_start;
2422 } while (start != temp || !num_read);
2423 if (n > 4) { /* NOT for fifth partition */
2424 struct pte *pe = &ptes[n];
2426 pe->offset_from_dev_start = start - sector_offset;
2427 if (pe->offset_from_dev_start == extended_offset) { /* must be corrected */
2428 pe->offset_from_dev_start++;
2429 if (sector_offset == 1)
2434 for (i = 0; i < g_partitions; i++) {
2435 struct pte *pe = &ptes[i];
2437 if (start < pe->offset_from_dev_start && limit >= pe->offset_from_dev_start)
2438 limit = pe->offset_from_dev_start - 1;
2439 if (start < first[i] && limit >= first[i])
2440 limit = first[i] - 1;
2442 if (start > limit) {
2443 puts("No free sectors available");
2448 if (cround(start) == cround(limit)) {
2451 snprintf(mesg, sizeof(mesg),
2452 "Last %s or +size or +sizeM or +sizeK",
2453 str_units(SINGULAR));
2454 stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg);
2455 if (display_in_cyl_units) {
2456 stop = stop * units_per_sector - 1;
2462 set_partition(n, 0, start, stop, sys);
2464 set_partition(n - 1, 1, ptes[n].offset_from_dev_start, stop, EXTENDED);
2466 if (IS_EXTENDED(sys)) {
2467 struct pte *pe4 = &ptes[4];
2468 struct pte *pen = &ptes[n];
2471 pen->ext_pointer = p;
2472 pe4->offset_from_dev_start = extended_offset = start;
2473 pe4->sectorbuffer = xzalloc(sector_size);
2474 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2475 pe4->ext_pointer = pe4->part_table + 1;
2484 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2485 struct pte *pe = &ptes[g_partitions];
2487 pe->sectorbuffer = xzalloc(sector_size);
2488 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2489 pe->ext_pointer = pe->part_table + 1;
2490 pe->offset_from_dev_start = 0;
2494 add_partition(g_partitions - 1, LINUX_NATIVE);
2500 int i, free_primary = 0;
2502 if (warn_geometry())
2506 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2510 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2514 puts("Sorry - this fdisk cannot handle AIX disk labels.\n"
2515 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2516 "table first (use 'o'). This will destroy the present disk contents.");
2520 for (i = 0; i < 4; i++)
2521 free_primary += !ptes[i].part_table->sys_ind;
2523 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2524 puts("The maximum number of partitions has been created");
2528 if (!free_primary) {
2529 if (extended_offset)
2532 puts("You must delete some partition and add "
2533 "an extended partition first");
2536 snprintf(line, sizeof(line),
2539 " p primary partition (1-4)\n",
2541 "l logical (5 or over)" : "e extended"));
2543 c = read_nonempty(line);
2544 if ((c | 0x20) == 'p') {
2545 i = get_nonexisting_partition(0, 4);
2547 add_partition(i, LINUX_NATIVE);
2550 if (c == 'l' && extended_offset) {
2554 if (c == 'e' && !extended_offset) {
2555 i = get_nonexisting_partition(0, 4);
2557 add_partition(i, EXTENDED);
2560 printf("Invalid partition number "
2561 "for type '%c'\n", c);
2567 reread_partition_table(int leave)
2571 puts("Calling ioctl() to re-read partition table");
2573 /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
2574 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
2577 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2578 "WARNING: rereading partition table "
2579 "failed, kernel still uses old table");
2583 "\nWARNING: If you have created or modified any DOS 6.x\n"
2584 "partitions, please see the fdisk manual page for additional\n"
2589 if (ENABLE_FEATURE_CLEAN_UP)
2601 for (i = 0; i < 3; i++)
2602 if (ptes[i].changed)
2603 ptes[3].changed = 1;
2604 for (i = 3; i < g_partitions; i++) {
2605 struct pte *pe = &ptes[i];
2607 write_part_table_flag(pe->sectorbuffer);
2608 write_sector(pe->offset_from_dev_start, pe->sectorbuffer);
2612 else if (LABEL_IS_SGI) {
2613 /* no test on change? the "altered" msg below might be mistaken */
2616 else if (LABEL_IS_SUN) {
2617 for (i = 0; i < 8; i++) {
2618 if (ptes[i].changed) {
2625 puts("The partition table has been altered.");
2626 reread_partition_table(1);
2628 #endif /* FEATURE_FDISK_WRITABLE */
2630 #if ENABLE_FEATURE_FDISK_ADVANCED
2631 #define MAX_PER_LINE 16
2633 print_buffer(char *pbuffer)
2637 for (i = 0, l = 0; i < sector_size; i++, l++) {
2639 printf("0x%03X:", i);
2640 printf(" %02X", (unsigned char) pbuffer[i]);
2641 if (l == MAX_PER_LINE - 1) {
2656 printf("Device: %s\n", disk_device);
2657 if (LABEL_IS_SGI || LABEL_IS_SUN)
2658 print_buffer(MBRbuffer);
2660 for (i = 3; i < g_partitions; i++)
2661 print_buffer(ptes[i].sectorbuffer);
2666 move_begin(unsigned i)
2668 struct pte *pe = &ptes[i];
2669 struct partition *p = pe->part_table;
2670 sector_t new, first, nr_sects;
2672 if (warn_geometry())
2674 nr_sects = get_nr_sects(p);
2675 if (!p->sys_ind || !nr_sects || IS_EXTENDED(p->sys_ind)) {
2676 printf("Partition %u has no data area\n", i + 1);
2679 first = get_partition_start_from_dev_start(pe); /* == pe->offset_from_dev_start + get_start_sect(p) */
2680 new = read_int(0 /*was:first*/, first, first + nr_sects - 1, first, "New beginning of data");
2682 sector_t new_relative = new - pe->offset_from_dev_start;
2683 nr_sects += (get_start_sect(p) - new_relative);
2684 set_start_sect(p, new_relative);
2685 set_nr_sects(p, nr_sects);
2686 read_nonempty("Recalculate C/H/S values? (Y/N): ");
2687 if ((line_ptr[0] | 0x20) == 'y')
2688 set_hsc_start_end(p, new, new + nr_sects - 1);
2700 c = 0x20 | read_nonempty("Expert command (m for help): ");
2708 move_begin(get_partition(0, g_partitions));
2711 user_cylinders = g_cylinders =
2712 read_int(1, g_cylinders, 1048576, 0,
2713 "Number of cylinders");
2715 sun_set_ncyl(g_cylinders);
2725 else if (LABEL_IS_SUN)
2727 else if (LABEL_IS_DOS)
2732 fix_partition_table_order();
2735 #if ENABLE_FEATURE_SGI_LABEL
2740 user_heads = g_heads = read_int(1, g_heads, 256, 0, "Number of heads");
2758 if (ENABLE_FEATURE_CLEAN_UP)
2765 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors");
2766 if (dos_compatible_flag) {
2767 sector_offset = g_sectors;
2768 puts("Warning: setting sector offset for DOS "
2777 write_table(); /* does not return */
2781 sun_set_pcylcount();
2788 #endif /* ADVANCED mode */
2791 is_ide_cdrom_or_tape(const char *device)
2795 struct stat statbuf;
2798 /* No device was given explicitly, and we are trying some
2799 likely things. But opening /dev/hdc may produce errors like
2800 "hdc: tray open or drive not ready"
2801 if it happens to be a CD-ROM drive. It even happens that
2802 the process hangs on the attempt to read a music CD.
2803 So try to be careful. This only works since 2.1.73. */
2805 if (!is_prefixed_with(device, "/dev/hd"))
2808 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2809 procf = fopen_for_read(buf);
2810 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2811 is_ide = (is_prefixed_with(buf, "cdrom") ||
2812 is_prefixed_with(buf, "tape"));
2814 /* Now when this proc file does not exist, skip the
2815 device when it is read-only. */
2816 if (stat(device, &statbuf) == 0)
2817 is_ide = ((statbuf.st_mode & 0222) == 0);
2826 open_list_and_close(const char *device, int user_specified)
2830 disk_device = device;
2831 if (setjmp(listingbuf))
2833 if (!user_specified)
2834 if (is_ide_cdrom_or_tape(device))
2837 /* Open disk_device, save file descriptor to dev_fd */
2839 gb = get_boot(TRY_ONLY);
2840 if (gb > 0) { /* I/O error */
2841 /* Ignore other errors, since we try IDE
2842 and SCSI hard disks which may not be
2843 installed on the system. */
2844 if (user_specified || errno == EACCES)
2845 bb_perror_msg("can't open '%s'", device);
2849 if (gb < 0) { /* no DOS signature */
2850 list_disk_geometry();
2853 #if ENABLE_FEATURE_OSF_LABEL
2854 if (bsd_trydev(device) < 0)
2856 printf("Disk %s doesn't contain a valid "
2857 "partition table\n", device);
2860 #if ENABLE_FEATURE_FDISK_WRITABLE
2861 if (!LABEL_IS_SUN && g_partitions > 4) {
2862 delete_partition(ext_index);
2870 /* Is it a whole disk? The digit check is still useful
2871 for Xen devices for example. */
2872 static int is_whole_disk(const char *disk)
2875 int fd = open(disk, O_RDONLY);
2878 struct hd_geometry geometry;
2879 int err = ioctl(fd, HDIO_GETGEO, &geometry);
2882 return (geometry.start == 0);
2885 /* Treat "nameN" as a partition name, not whole disk */
2886 /* note: mmcblk0 should work from the geometry check above */
2888 if (len != 0 && isdigit(disk[len - 1]))
2894 /* for fdisk -l: try all things in /proc/partitions
2895 that look like a partition name (do not end in a digit) */
2897 list_devs_in_proc_partititons(void)
2900 char line[100], ptname[100], devname[120];
2903 procpt = fopen_or_warn("/proc/partitions", "r");
2905 while (fgets(line, sizeof(line), procpt)) {
2906 if (sscanf(line, " %u %u %u %[^\n ]",
2907 &ma, &mi, &sz, ptname) != 4)
2910 sprintf(devname, "/dev/%s", ptname);
2911 if (is_whole_disk(devname))
2912 open_list_and_close(devname, 0);
2914 #if ENABLE_FEATURE_CLEAN_UP
2919 #if ENABLE_FEATURE_FDISK_WRITABLE
2921 unknown_command(int c)
2923 printf("%c: unknown command\n", c);
2927 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2928 int fdisk_main(int argc UNUSED_PARAM, char **argv)
2933 * fdisk -l [-b sectorsize] [-u] device ...
2934 * fdisk -s [partition] ...
2935 * fdisk [-b sectorsize] [-u] device
2937 * Options -C, -H, -S set the geometry.
2941 close_dev_fd(); /* needed: fd 3 must not stay closed */
2943 opt = getopt32(argv, "b:+C:+H:+lS:+u" IF_FEATURE_FDISK_BLKSIZE("s"),
2944 §or_size, &user_cylinders, &user_heads, &user_sectors);
2947 /* Ugly: this sector size is really per device,
2948 * so cannot be combined with multiple disks,
2949 * and the same goes for the C/H/S options.
2951 if (sector_size < 512
2952 || sector_size > 0x10000
2953 || (sector_size & (sector_size-1)) /* not power of 2 */
2958 user_set_sector_size = 1;
2960 if (user_heads <= 0 || user_heads >= 256)
2962 if (user_sectors <= 0 || user_sectors >= 64)
2965 display_in_cyl_units = 0; // -u
2967 #if ENABLE_FEATURE_FDISK_WRITABLE
2974 open_list_and_close(*argv, 1);
2977 /* we don't have device names, */
2978 /* use /proc/partitions instead */
2979 list_devs_in_proc_partititons();
2982 #if ENABLE_FEATURE_FDISK_WRITABLE
2986 #if ENABLE_FEATURE_FDISK_BLKSIZE
2993 for (j = 0; argv[j]; j++) {
2994 unsigned long long size;
2995 fd = xopen(argv[j], O_RDONLY);
2996 size = bb_BLKGETSIZE_sectors(fd) / 2;
2999 printf("%llu\n", size);
3001 printf("%s: %llu\n", argv[j], size);
3007 #if ENABLE_FEATURE_FDISK_WRITABLE
3008 if (!argv[0] || argv[1])
3011 disk_device = argv[0];
3012 get_boot(OPEN_MAIN);
3015 /* OSF label, and no DOS label */
3016 printf("Detected an OSF/1 disklabel on %s, entering "
3017 "disklabel mode\n", disk_device);
3019 /*Why do we do this? It seems to be counter-intuitive*/
3020 current_label_type = LABEL_DOS;
3021 /* If we return we may want to make an empty DOS label? */
3027 c = 0x20 | read_nonempty("Command (m for help): ");
3031 toggle_active(get_partition(1, g_partitions));
3032 else if (LABEL_IS_SUN)
3033 toggle_sunflags(get_partition(1, g_partitions),
3035 else if (LABEL_IS_SGI)
3036 sgi_set_bootpartition(
3037 get_partition(1, g_partitions));
3043 printf("\nThe current boot file is: %s\n",
3044 sgi_get_bootfile());
3045 if (read_maybe_empty("Please enter the name of the "
3046 "new boot file: ") == '\n')
3047 puts("Boot file unchanged");
3049 sgi_set_bootfile(line_ptr);
3051 #if ENABLE_FEATURE_OSF_LABEL
3058 toggle_dos_compatibility_flag();
3059 else if (LABEL_IS_SUN)
3060 toggle_sunflags(get_partition(1, g_partitions),
3062 else if (LABEL_IS_SGI)
3063 sgi_set_swappartition(
3064 get_partition(1, g_partitions));
3071 /* If sgi_label then don't use get_existing_partition,
3072 let the user select a partition, since
3073 get_existing_partition() only works for Linux-like
3075 if (!LABEL_IS_SGI) {
3076 j = get_existing_partition(1, g_partitions);
3078 j = get_partition(1, g_partitions);
3081 delete_partition(j);
3090 list_types(get_sys_types());
3105 if (ENABLE_FEATURE_CLEAN_UP)
3110 #if ENABLE_FEATURE_SUN_LABEL
3124 write_table(); /* does not return */
3126 #if ENABLE_FEATURE_FDISK_ADVANCED
3129 puts("\n\tSorry, no experts menu for SGI "
3130 "partition tables available\n");
3141 #endif /* FEATURE_FDISK_WRITABLE */