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 /* Return partition name */
478 partname(const char *dev, int pno, int lth)
485 bufp = auto_string(xzalloc(80));
491 if (isdigit(dev[w-1]))
494 /* devfs kludge - note: fdisk partition names are not supposed
495 to equal kernel names, so there is no reason to do this */
496 if (strcmp(dev + w - 4, "disc") == 0) {
504 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
505 lth-wp-2, w, dev, p, pno);
507 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
512 static ALWAYS_INLINE struct partition *
513 get_part_table(int i)
515 return ptes[i].part_table;
520 { /* n==1: use singular */
522 return display_in_cyl_units ? "cylinder" : "sector";
523 return display_in_cyl_units ? "cylinders" : "sectors";
527 valid_part_table_flag(const char *mbuffer)
529 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
532 static void fdisk_fatal(const char *why)
536 longjmp(listingbuf, 1);
538 bb_error_msg_and_die(why, disk_device);
542 seek_sector(sector_t secno)
544 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
545 off64_t off = (off64_t)secno * sector_size;
546 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
547 fdisk_fatal(unable_to_seek);
549 uint64_t off = (uint64_t)secno * sector_size;
550 if (off > MAXINT(off_t)
551 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
553 fdisk_fatal(unable_to_seek);
558 #if ENABLE_FEATURE_FDISK_WRITABLE
559 /* Read line; return 0 or first printable char */
561 read_line(const char *prompt)
565 sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
567 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
569 if (line_buffer[sz-1] == '\n')
570 line_buffer[--sz] = '\0';
572 line_ptr = line_buffer;
573 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
579 set_all_unchanged(void)
583 for (i = 0; i < MAXIMUM_PARTS; i++)
587 static ALWAYS_INLINE void
593 static ALWAYS_INLINE void
594 write_part_table_flag(char *b)
601 read_nonempty(const char *mesg)
603 while (!read_line(mesg))
609 read_maybe_empty(const char *mesg)
611 if (!read_line(mesg)) {
612 line_ptr = line_buffer;
620 read_hex(const char *const *sys)
624 read_nonempty("Hex code (type L to list codes): ");
625 if ((line_ptr[0] | 0x20) == 'l') {
629 v = bb_strtoul(line_ptr, NULL, 16);
636 write_sector(sector_t secno, const void *buf)
639 xwrite(dev_fd, buf, sector_size);
641 #endif /* FEATURE_FDISK_WRITABLE */
644 #include "fdisk_aix.c"
646 struct sun_partition {
647 unsigned char info[128]; /* Informative text string */
648 unsigned char spare0[14];
650 unsigned char spare1;
652 unsigned char spare2;
655 unsigned char spare1[246]; /* Boot information etc. */
656 unsigned short rspeed; /* Disk rotational speed */
657 unsigned short pcylcount; /* Physical cylinder count */
658 unsigned short sparecyl; /* extra sects per cylinder */
659 unsigned char spare2[4]; /* More magic... */
660 unsigned short ilfact; /* Interleave factor */
661 unsigned short ncyl; /* Data cylinder count */
662 unsigned short nacyl; /* Alt. cylinder count */
663 unsigned short ntrks; /* Tracks per cylinder */
664 unsigned short nsect; /* Sectors per track */
665 unsigned char spare3[4]; /* Even more magic... */
666 struct sun_partinfo {
667 uint32_t start_cylinder;
668 uint32_t num_sectors;
670 unsigned short magic; /* Magic number */
671 unsigned short csum; /* Label xor'd checksum */
673 typedef struct sun_partition sun_partition;
674 #define sunlabel ((sun_partition *)MBRbuffer)
675 STATIC_OSF void bsd_select(void);
676 STATIC_OSF void xbsd_print_disklabel(int);
677 #include "fdisk_osf.c"
679 STATIC_GPT void gpt_list_table(int xtra);
680 #include "fdisk_gpt.c"
682 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
684 fdisk_swap16(uint16_t x)
686 return (x << 8) | (x >> 8);
690 fdisk_swap32(uint32_t x)
693 ((x & 0xFF00) << 8) |
694 ((x & 0xFF0000) >> 8) |
699 STATIC_SGI const char *const sgi_sys_types[];
700 STATIC_SGI unsigned sgi_get_num_sectors(int i);
701 STATIC_SGI int sgi_get_sysid(int i);
702 STATIC_SGI void sgi_delete_partition(int i);
703 STATIC_SGI void sgi_change_sysid(int i, int sys);
704 STATIC_SGI void sgi_list_table(int xtra);
705 #if ENABLE_FEATURE_FDISK_ADVANCED
706 STATIC_SGI void sgi_set_xcyl(void);
708 STATIC_SGI int verify_sgi(int verbose);
709 STATIC_SGI void sgi_add_partition(int n, int sys);
710 STATIC_SGI void sgi_set_swappartition(int i);
711 STATIC_SGI const char *sgi_get_bootfile(void);
712 STATIC_SGI void sgi_set_bootfile(const char* aFile);
713 STATIC_SGI void create_sgiinfo(void);
714 STATIC_SGI void sgi_write_table(void);
715 STATIC_SGI void sgi_set_bootpartition(int i);
716 #include "fdisk_sgi.c"
718 STATIC_SUN const char *const sun_sys_types[];
719 STATIC_SUN void sun_delete_partition(int i);
720 STATIC_SUN void sun_change_sysid(int i, int sys);
721 STATIC_SUN void sun_list_table(int xtra);
722 STATIC_SUN void add_sun_partition(int n, int sys);
723 #if ENABLE_FEATURE_FDISK_ADVANCED
724 STATIC_SUN void sun_set_alt_cyl(void);
725 STATIC_SUN void sun_set_ncyl(int cyl);
726 STATIC_SUN void sun_set_xcyl(void);
727 STATIC_SUN void sun_set_ilfact(void);
728 STATIC_SUN void sun_set_rspeed(void);
729 STATIC_SUN void sun_set_pcylcount(void);
731 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
732 STATIC_SUN void verify_sun(void);
733 STATIC_SUN void sun_write_table(void);
734 #include "fdisk_sun.c"
737 static inline_if_little_endian unsigned
738 read4_little_endian(const unsigned char *cp)
741 move_from_unaligned32(v, cp);
746 get_start_sect(const struct partition *p)
748 return read4_little_endian(p->start4);
752 get_nr_sects(const struct partition *p)
754 return read4_little_endian(p->size4);
757 #if ENABLE_FEATURE_FDISK_WRITABLE
758 /* start_sect and nr_sects are stored little endian on all machines */
759 /* moreover, they are not aligned correctly */
760 static inline_if_little_endian void
761 store4_little_endian(unsigned char *cp, unsigned val)
763 uint32_t v = SWAP_LE32(val);
764 move_to_unaligned32(cp, v);
768 set_start_sect(struct partition *p, unsigned start_sect)
770 store4_little_endian(p->start4, start_sect);
774 set_nr_sects(struct partition *p, unsigned nr_sects)
776 store4_little_endian(p->size4, nr_sects);
780 /* Allocate a buffer and read a partition table sector */
782 read_pte(struct pte *pe, sector_t offset)
784 pe->offset_from_dev_start = offset;
785 pe->sectorbuffer = xzalloc(sector_size);
787 /* xread would make us abort - bad for fdisk -l */
788 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
789 fdisk_fatal(unable_to_read);
790 #if ENABLE_FEATURE_FDISK_WRITABLE
793 pe->part_table = pe->ext_pointer = NULL;
797 get_partition_start_from_dev_start(const struct pte *pe)
799 return pe->offset_from_dev_start + get_start_sect(pe->part_table);
802 #if ENABLE_FEATURE_FDISK_WRITABLE
804 * Avoid warning about DOS partitions when no DOS partition was changed.
805 * Here a heuristic "is probably dos partition".
806 * We might also do the opposite and warn in all cases except
807 * for "is probably nondos partition".
811 is_dos_partition(int t)
813 return (t == 1 || t == 4 || t == 6 ||
814 t == 0x0b || t == 0x0c || t == 0x0e ||
815 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
816 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
817 t == 0xc1 || t == 0xc4 || t == 0xc6);
824 puts("Command Action");
826 puts("a\ttoggle a read only flag"); /* sun */
827 puts("b\tedit bsd disklabel");
828 puts("c\ttoggle the mountable flag"); /* sun */
829 puts("d\tdelete a partition");
830 puts("l\tlist known partition types");
831 puts("n\tadd a new partition");
832 puts("o\tcreate a new empty DOS partition table");
833 puts("p\tprint the partition table");
834 puts("q\tquit without saving changes");
835 puts("s\tcreate a new empty Sun disklabel"); /* sun */
836 puts("t\tchange a partition's system id");
837 puts("u\tchange display/entry units");
838 puts("v\tverify the partition table");
839 puts("w\twrite table to disk and exit");
840 #if ENABLE_FEATURE_FDISK_ADVANCED
841 puts("x\textra functionality (experts only)");
843 } else if (LABEL_IS_SGI) {
844 puts("a\tselect bootable partition"); /* sgi flavour */
845 puts("b\tedit bootfile entry"); /* sgi */
846 puts("c\tselect sgi swap partition"); /* sgi flavour */
847 puts("d\tdelete a partition");
848 puts("l\tlist known partition types");
849 puts("n\tadd a new partition");
850 puts("o\tcreate a new empty DOS partition table");
851 puts("p\tprint the partition table");
852 puts("q\tquit without saving changes");
853 puts("s\tcreate a new empty Sun disklabel"); /* sun */
854 puts("t\tchange a partition's system id");
855 puts("u\tchange display/entry units");
856 puts("v\tverify the partition table");
857 puts("w\twrite table to disk and exit");
858 } else if (LABEL_IS_AIX) {
859 puts("o\tcreate a new empty DOS partition table");
860 puts("q\tquit without saving changes");
861 puts("s\tcreate a new empty Sun disklabel"); /* sun */
862 } else if (LABEL_IS_GPT) {
863 puts("o\tcreate a new empty DOS partition table");
864 puts("p\tprint the partition table");
865 puts("q\tquit without saving changes");
866 puts("s\tcreate a new empty Sun disklabel"); /* sun */
868 puts("a\ttoggle a bootable flag");
869 puts("b\tedit bsd disklabel");
870 puts("c\ttoggle the dos compatibility flag");
871 puts("d\tdelete a partition");
872 puts("l\tlist known partition types");
873 puts("n\tadd a new partition");
874 puts("o\tcreate a new empty DOS partition table");
875 puts("p\tprint the partition table");
876 puts("q\tquit without saving changes");
877 puts("s\tcreate a new empty Sun disklabel"); /* sun */
878 puts("t\tchange a partition's system id");
879 puts("u\tchange display/entry units");
880 puts("v\tverify the partition table");
881 puts("w\twrite table to disk and exit");
882 #if ENABLE_FEATURE_FDISK_ADVANCED
883 puts("x\textra functionality (experts only)");
887 #endif /* FEATURE_FDISK_WRITABLE */
890 #if ENABLE_FEATURE_FDISK_ADVANCED
894 puts("Command Action");
896 puts("a\tchange number of alternate cylinders"); /*sun*/
897 puts("c\tchange number of cylinders");
898 puts("d\tprint the raw data in the partition table");
899 puts("e\tchange number of extra sectors per cylinder");/*sun*/
900 puts("h\tchange number of heads");
901 puts("i\tchange interleave factor"); /*sun*/
902 puts("o\tchange rotation speed (rpm)"); /*sun*/
903 puts("p\tprint the partition table");
904 puts("q\tquit without saving changes");
905 puts("r\treturn to main menu");
906 puts("s\tchange number of sectors/track");
907 puts("v\tverify the partition table");
908 puts("w\twrite table to disk and exit");
909 puts("y\tchange number of physical cylinders"); /*sun*/
910 } else if (LABEL_IS_SGI) {
911 puts("b\tmove beginning of data in a partition"); /* !sun */
912 puts("c\tchange number of cylinders");
913 puts("d\tprint the raw data in the partition table");
914 puts("e\tlist extended partitions"); /* !sun */
915 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
916 puts("h\tchange number of heads");
917 puts("p\tprint the partition table");
918 puts("q\tquit without saving changes");
919 puts("r\treturn to main menu");
920 puts("s\tchange number of sectors/track");
921 puts("v\tverify the partition table");
922 puts("w\twrite table to disk and exit");
923 } else if (LABEL_IS_AIX) {
924 puts("b\tmove beginning of data in a partition"); /* !sun */
925 puts("c\tchange number of cylinders");
926 puts("d\tprint the raw data in the partition table");
927 puts("e\tlist extended partitions"); /* !sun */
928 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
929 puts("h\tchange number of heads");
930 puts("p\tprint the partition table");
931 puts("q\tquit without saving changes");
932 puts("r\treturn to main menu");
933 puts("s\tchange number of sectors/track");
934 puts("v\tverify the partition table");
935 puts("w\twrite table to disk and exit");
937 puts("b\tmove beginning of data in a partition"); /* !sun */
938 puts("c\tchange number of cylinders");
939 puts("d\tprint the raw data in the partition table");
940 puts("e\tlist extended partitions"); /* !sun */
941 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
942 #if ENABLE_FEATURE_SGI_LABEL
943 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
945 puts("h\tchange number of heads");
946 puts("p\tprint the partition table");
947 puts("q\tquit without saving changes");
948 puts("r\treturn to main menu");
949 puts("s\tchange number of sectors/track");
950 puts("v\tverify the partition table");
951 puts("w\twrite table to disk and exit");
954 #endif /* ADVANCED mode */
956 #if ENABLE_FEATURE_FDISK_WRITABLE
957 static const char *const *
961 LABEL_IS_SUN ? sun_sys_types :
962 LABEL_IS_SGI ? sgi_sys_types :
966 #define get_sys_types() i386_sys_types
970 partition_type(unsigned char type)
973 const char *const *types = get_sys_types();
975 for (i = 0; types[i]; i++)
976 if ((unsigned char)types[i][0] == type)
983 is_cleared_partition(const struct partition *p)
985 /* We consider partition "cleared" only if it has only zeros */
986 const char *cp = (const char *)p;
987 int cnt = sizeof(*p);
995 clear_partition(struct partition *p)
998 memset(p, 0, sizeof(*p));
1001 #if ENABLE_FEATURE_FDISK_WRITABLE
1005 return LABEL_IS_SUN ? sunlabel->infos[i].id :
1006 (LABEL_IS_SGI ? sgi_get_sysid(i) :
1007 ptes[i].part_table->sys_ind);
1011 list_types(const char *const *sys)
1015 unsigned last[COLS];
1016 unsigned done, next, size;
1019 for (size = 0; sys[size]; size++)
1023 for (i = COLS-1; i >= 0; i--) {
1024 done += (size + i - done) / (i + 1);
1025 last[COLS-1 - i] = done;
1028 i = done = next = 0;
1030 printf("%c%2x %-22.22s", i ? ' ' : '\n',
1031 (unsigned char)sys[next][0],
1033 next = last[i++] + done;
1034 if (i >= COLS || next >= last[i]) {
1038 } while (done < last[0]);
1042 #define set_hsc(h, s, c, sector) do \
1044 s = sector % g_sectors + 1; \
1045 sector /= g_sectors; \
1046 h = sector % g_heads; \
1047 sector /= g_heads; \
1048 c = sector & 0xff; \
1049 s |= (sector >> 2) & 0xc0; \
1052 static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop)
1054 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1055 start = g_heads * g_sectors * 1024 - 1;
1056 set_hsc(p->head, p->sector, p->cyl, start);
1058 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1059 stop = g_heads * g_sectors * 1024 - 1;
1060 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1064 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1066 struct partition *p;
1070 p = ptes[i].ext_pointer;
1071 offset = extended_offset;
1073 p = ptes[i].part_table;
1074 offset = ptes[i].offset_from_dev_start;
1078 set_start_sect(p, start - offset);
1079 set_nr_sects(p, stop - start + 1);
1080 set_hsc_start_end(p, start, stop);
1081 ptes[i].changed = 1;
1088 if (g_heads && g_sectors && g_cylinders)
1091 printf("Unknown value(s) for:");
1097 printf(" cylinders");
1098 #if ENABLE_FEATURE_FDISK_WRITABLE
1099 puts(" (settable in the extra functions menu)");
1109 int cyl_units = g_heads * g_sectors;
1111 if (display_in_cyl_units && cyl_units)
1112 units_per_sector = cyl_units;
1114 units_per_sector = 1; /* in sectors */
1117 #if ENABLE_FEATURE_FDISK_WRITABLE
1119 warn_cylinders(void)
1121 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1123 "The number of cylinders for this disk is set to %u.\n"
1124 "There is nothing wrong with that, but this is larger than 1024,\n"
1125 "and could in certain setups cause problems with:\n"
1126 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1127 "2) booting and partitioning software from other OSs\n"
1128 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1134 read_extended(int ext)
1138 struct partition *p, *q;
1142 pex->ext_pointer = pex->part_table;
1144 p = pex->part_table;
1145 if (!get_start_sect(p)) {
1146 puts("Bad offset in primary extended partition");
1150 while (IS_EXTENDED(p->sys_ind)) {
1151 struct pte *pe = &ptes[g_partitions];
1153 if (g_partitions >= MAXIMUM_PARTS) {
1154 /* This is not a Linux restriction, but
1155 this program uses arrays of size MAXIMUM_PARTS.
1156 Do not try to 'improve' this test. */
1157 struct pte *pre = &ptes[g_partitions - 1];
1158 #if ENABLE_FEATURE_FDISK_WRITABLE
1159 printf("Warning: deleting partitions after %u\n",
1163 clear_partition(pre->ext_pointer);
1167 read_pte(pe, extended_offset + get_start_sect(p));
1169 if (!extended_offset)
1170 extended_offset = get_start_sect(p);
1172 q = p = pt_offset(pe->sectorbuffer, 0);
1173 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1174 if (IS_EXTENDED(p->sys_ind)) {
1175 if (pe->ext_pointer)
1176 printf("Warning: extra link "
1177 "pointer in partition table"
1178 " %u\n", g_partitions + 1);
1180 pe->ext_pointer = p;
1181 } else if (p->sys_ind) {
1183 printf("Warning: ignoring extra "
1184 "data in partition table"
1185 " %u\n", g_partitions + 1);
1191 /* very strange code here... */
1192 if (!pe->part_table) {
1193 if (q != pe->ext_pointer)
1196 pe->part_table = q + 1;
1198 if (!pe->ext_pointer) {
1199 if (q != pe->part_table)
1200 pe->ext_pointer = q;
1202 pe->ext_pointer = q + 1;
1205 p = pe->ext_pointer;
1209 #if ENABLE_FEATURE_FDISK_WRITABLE
1210 /* remove empty links */
1212 for (i = 4; i < g_partitions; i++) {
1213 struct pte *pe = &ptes[i];
1215 if (!get_nr_sects(pe->part_table)
1216 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1218 printf("Omitting empty partition (%u)\n", i+1);
1219 delete_partition(i);
1220 goto remove; /* numbering changed */
1226 #if ENABLE_FEATURE_FDISK_WRITABLE
1228 create_doslabel(void)
1230 printf(msg_building_new_label, "DOS disklabel");
1232 current_label_type = LABEL_DOS;
1233 #if ENABLE_FEATURE_OSF_LABEL
1234 possibly_osf_label = 0;
1238 memset(&MBRbuffer[510 - 4*16], 0, 4*16);
1239 write_part_table_flag(MBRbuffer);
1240 extended_offset = 0;
1241 set_all_unchanged();
1243 get_boot(CREATE_EMPTY_DOS);
1248 get_sectorsize(void)
1250 if (!user_set_sector_size) {
1252 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1254 if (sector_size != DEFAULT_SECTOR_SIZE)
1255 printf("Note: sector size is %u "
1256 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1262 get_kernel_geometry(void)
1264 struct hd_geometry geometry;
1266 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1267 kern_heads = geometry.heads;
1268 kern_sectors = geometry.sectors;
1269 /* never use geometry.cylinders - it is truncated */
1274 get_partition_table_geometry(void)
1276 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1277 struct partition *p;
1278 int i, h, s, hh, ss;
1282 if (!(valid_part_table_flag((char*)bufp)))
1286 for (i = 0; i < 4; i++) {
1287 p = pt_offset(bufp, i);
1288 if (p->sys_ind != 0) {
1289 h = p->end_head + 1;
1290 s = (p->end_sector & 077);
1295 } else if (hh != h || ss != s)
1300 if (!first && !bad) {
1312 sec_fac = sector_size / 512;
1313 #if ENABLE_FEATURE_SUN_LABEL
1314 guess_device_type();
1316 g_heads = g_cylinders = g_sectors = 0;
1317 kern_heads = kern_sectors = 0;
1318 pt_heads = pt_sectors = 0;
1320 get_kernel_geometry();
1321 get_partition_table_geometry();
1323 g_heads = user_heads ? user_heads :
1324 pt_heads ? pt_heads :
1325 kern_heads ? kern_heads : 255;
1326 g_sectors = user_sectors ? user_sectors :
1327 pt_sectors ? pt_sectors :
1328 kern_sectors ? kern_sectors : 63;
1329 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1332 if (dos_compatible_flag)
1333 sector_offset = g_sectors;
1335 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1337 g_cylinders = user_cylinders;
1341 * Opens disk_device and optionally reads MBR.
1342 * If what == OPEN_MAIN:
1343 * Open device, read MBR. Abort program on short read. Create empty
1344 * disklabel if the on-disk structure is invalid (WRITABLE mode).
1345 * If what == TRY_ONLY:
1346 * Open device, read MBR. Return an error if anything is out of place.
1347 * Do not create an empty disklabel. This is used for the "list"
1348 * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
1349 * If what == CREATE_EMPTY_*:
1350 * This means that get_boot() was called recursively from create_*label().
1351 * Do not re-open the device; just set up the ptes array and print
1352 * geometry warnings.
1355 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1356 * 0: found or created label
1359 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1360 static int get_boot(enum action what)
1362 static int get_boot(void)
1363 #define get_boot(what) get_boot()
1369 for (i = 0; i < 4; i++) {
1370 struct pte *pe = &ptes[i];
1371 pe->part_table = pt_offset(MBRbuffer, i);
1372 pe->ext_pointer = NULL;
1373 pe->offset_from_dev_start = 0;
1374 pe->sectorbuffer = MBRbuffer;
1375 #if ENABLE_FEATURE_FDISK_WRITABLE
1376 pe->changed = (what == CREATE_EMPTY_DOS);
1380 #if ENABLE_FEATURE_FDISK_WRITABLE
1381 // ALERT! highly idiotic design!
1382 // We end up here when we call get_boot() recursively
1383 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1384 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1385 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1386 // So skip opening device _again_...
1387 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1390 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1393 fd = open(disk_device, O_RDONLY);
1395 if (what == TRY_ONLY)
1397 fdisk_fatal(unable_to_open);
1399 printf("'%s' is opened for read only\n", disk_device);
1401 xmove_fd(fd, dev_fd);
1402 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1403 if (what == TRY_ONLY) {
1407 fdisk_fatal(unable_to_read);
1410 fd = open(disk_device, O_RDONLY);
1413 if (512 != full_read(fd, MBRbuffer, 512)) {
1417 xmove_fd(fd, dev_fd);
1423 #if ENABLE_FEATURE_SUN_LABEL
1424 if (check_sun_label())
1427 #if ENABLE_FEATURE_SGI_LABEL
1428 if (check_sgi_label())
1431 #if ENABLE_FEATURE_AIX_LABEL
1432 if (check_aix_label())
1435 #if ENABLE_FEATURE_GPT_LABEL
1436 if (check_gpt_label())
1439 #if ENABLE_FEATURE_OSF_LABEL
1440 if (check_osf_label()) {
1441 possibly_osf_label = 1;
1442 if (!valid_part_table_flag(MBRbuffer)) {
1443 current_label_type = LABEL_OSF;
1446 puts("This disk has both DOS and BSD magic.\n"
1447 "Give the 'b' command to go to BSD mode.");
1451 #if !ENABLE_FEATURE_FDISK_WRITABLE
1452 if (!valid_part_table_flag(MBRbuffer))
1455 if (!valid_part_table_flag(MBRbuffer)) {
1456 if (what == OPEN_MAIN) {
1457 puts("Device contains neither a valid DOS "
1458 "partition table, nor Sun, SGI, OSF or GPT "
1461 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1471 #endif /* FEATURE_FDISK_WRITABLE */
1474 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1477 for (i = 0; i < 4; i++) {
1478 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1479 if (g_partitions != 4)
1480 printf("Ignoring extra extended "
1481 "partition %u\n", i + 1);
1487 for (i = 3; i < g_partitions; i++) {
1488 struct pte *pe = &ptes[i];
1489 if (!valid_part_table_flag(pe->sectorbuffer)) {
1490 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1491 "table %u will be corrected by w(rite)\n",
1492 pe->sectorbuffer[510],
1493 pe->sectorbuffer[511],
1495 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1502 #if ENABLE_FEATURE_FDISK_WRITABLE
1504 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1505 * If the user hits Enter, DFLT is returned.
1506 * Answers like +10 are interpreted as offsets from BASE.
1508 * There is no default if DFLT is not between LOW and HIGH.
1511 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1515 const char *fmt = "%s (%u-%u, default %u): ";
1517 if (dflt < low || dflt > high) {
1518 fmt = "%s (%u-%u): ";
1523 int use_default = default_ok;
1525 /* ask question and read answer */
1527 printf(fmt, mesg, low, high, dflt);
1528 read_maybe_empty("");
1529 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1530 && *line_ptr != '-' && *line_ptr != '+');
1532 if (*line_ptr == '+' || *line_ptr == '-') {
1533 int minus = (*line_ptr == '-');
1536 value = atoi(line_ptr + 1);
1538 /* (1) if 2nd char is digit, use_default = 0.
1539 * (2) move line_ptr to first non-digit. */
1540 while (isdigit(*++line_ptr))
1543 switch (*line_ptr) {
1546 if (!display_in_cyl_units)
1547 value *= g_heads * g_sectors;
1561 absolute = 1000000000;
1570 bytes = (ullong) value * absolute;
1571 unit = sector_size * units_per_sector;
1572 bytes += unit/2; /* round */
1580 value = atoi(line_ptr);
1581 while (isdigit(*line_ptr)) {
1588 printf("Using default value %u\n", value);
1590 if (value >= low && value <= high)
1592 puts("Value is out of range");
1598 get_partition(int warn, unsigned max)
1603 i = read_int(1, 0, max, 0, "Partition number") - 1;
1607 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1608 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1609 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1611 printf("Warning: partition %u has empty type\n", i+1);
1618 get_existing_partition(int warn, unsigned max)
1623 for (i = 0; i < max; i++) {
1624 struct pte *pe = &ptes[i];
1625 struct partition *p = pe->part_table;
1627 if (p && !is_cleared_partition(p)) {
1634 printf("Selected partition %u\n", pno+1);
1637 puts("No partition is defined yet!");
1641 return get_partition(warn, max);
1645 get_nonexisting_partition(int warn, unsigned max)
1650 for (i = 0; i < max; i++) {
1651 struct pte *pe = &ptes[i];
1652 struct partition *p = pe->part_table;
1654 if (p && is_cleared_partition(p)) {
1661 printf("Selected partition %u\n", pno+1);
1664 puts("All primary partitions have been defined already!");
1668 return get_partition(warn, max);
1675 display_in_cyl_units = !display_in_cyl_units;
1677 printf("Changing display/entry units to %s\n",
1682 toggle_active(int i)
1684 struct pte *pe = &ptes[i];
1685 struct partition *p = pe->part_table;
1687 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1688 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1689 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1694 toggle_dos_compatibility_flag(void)
1696 dos_compatible_flag = 1 - dos_compatible_flag;
1697 if (dos_compatible_flag) {
1698 sector_offset = g_sectors;
1699 printf("DOS Compatibility flag is %sset\n", "");
1702 printf("DOS Compatibility flag is %sset\n", "not ");
1707 delete_partition(int i)
1709 struct pte *pe = &ptes[i];
1710 struct partition *p = pe->part_table;
1711 struct partition *q = pe->ext_pointer;
1713 /* Note that for the fifth partition (i == 4) we don't actually
1714 * decrement partitions.
1717 if (warn_geometry())
1718 return; /* C/H/S not set */
1722 sun_delete_partition(i);
1726 sgi_delete_partition(i);
1731 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1733 ptes[ext_index].ext_pointer = NULL;
1734 extended_offset = 0;
1740 if (!q->sys_ind && i > 4) {
1741 /* the last one in the chain - just delete */
1744 clear_partition(ptes[i].ext_pointer);
1745 ptes[i].changed = 1;
1747 /* not the last one - further ones will be moved down */
1749 /* delete this link in the chain */
1750 p = ptes[i-1].ext_pointer;
1752 set_start_sect(p, get_start_sect(q));
1753 set_nr_sects(p, get_nr_sects(q));
1754 ptes[i-1].changed = 1;
1755 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1756 /* the first logical in a longer chain */
1759 if (pe->part_table) /* prevent SEGFAULT */
1760 set_start_sect(pe->part_table,
1761 get_partition_start_from_dev_start(pe) -
1763 pe->offset_from_dev_start = extended_offset;
1767 if (g_partitions > 5) {
1769 while (i < g_partitions) {
1770 ptes[i] = ptes[i+1];
1774 /* the only logical: clear only */
1775 clear_partition(ptes[i].part_table);
1783 int i, sys, origsys;
1784 struct partition *p;
1786 /* If sgi_label then don't use get_existing_partition,
1787 let the user select a partition, since get_existing_partition()
1788 only works for Linux like partition tables. */
1789 if (!LABEL_IS_SGI) {
1790 i = get_existing_partition(0, g_partitions);
1792 i = get_partition(0, g_partitions);
1796 p = ptes[i].part_table;
1797 origsys = sys = get_sysid(i);
1799 /* if changing types T to 0 is allowed, then
1800 the reverse change must be allowed, too */
1801 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1802 printf("Partition %u does not exist yet!\n", i + 1);
1806 sys = read_hex(get_sys_types());
1808 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1809 puts("Type 0 means free space to many systems\n"
1810 "(but not to Linux). Having partitions of\n"
1811 "type 0 is probably unwise.");
1815 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1816 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1817 puts("You cannot change a partition into"
1818 " an extended one or vice versa");
1824 #if ENABLE_FEATURE_SUN_LABEL
1825 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1826 puts("Consider leaving partition 3 "
1827 "as Whole disk (5),\n"
1828 "as SunOS/Solaris expects it and "
1829 "even Linux likes it\n");
1831 #if ENABLE_FEATURE_SGI_LABEL
1834 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1835 (i == 8 && sys != 0)
1838 puts("Consider leaving partition 9 "
1839 "as volume header (0),\nand "
1840 "partition 11 as entire volume (6)"
1841 "as IRIX expects it\n");
1847 sun_change_sysid(i, sys);
1848 } else if (LABEL_IS_SGI) {
1849 sgi_change_sysid(i, sys);
1853 printf("Changed system type of partition %u "
1854 "to %x (%s)\n", i + 1, sys,
1855 partition_type(sys));
1856 ptes[i].changed = 1;
1857 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1863 #endif /* FEATURE_FDISK_WRITABLE */
1866 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1867 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1868 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1869 * Lubkin Oct. 1991). */
1872 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1874 int spc = g_heads * g_sectors;
1878 *h = ls / g_sectors;
1879 *s = ls % g_sectors + 1; /* sectors count from 1 */
1883 check_consistency(const struct partition *p, int partition)
1885 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1886 unsigned pec, peh, pes; /* physical ending c, h, s */
1887 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1888 unsigned lec, leh, les; /* logical ending c, h, s */
1890 if (!g_heads || !g_sectors || (partition >= 4))
1891 return; /* do not check extended partitions */
1893 /* physical beginning c, h, s */
1894 pbc = cylinder(p->sector, p->cyl);
1896 pbs = sector(p->sector);
1898 /* physical ending c, h, s */
1899 pec = cylinder(p->end_sector, p->end_cyl);
1901 pes = sector(p->end_sector);
1903 /* compute logical beginning (c, h, s) */
1904 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1906 /* compute logical ending (c, h, s) */
1907 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1909 /* Same physical / logical beginning? */
1910 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1911 printf("Partition %u has different physical/logical "
1912 "start (non-Linux?):\n", partition + 1);
1913 printf(" phys=(%u,%u,%u) ", pbc, pbh, pbs);
1914 printf("logical=(%u,%u,%u)\n", lbc, lbh, lbs);
1917 /* Same physical / logical ending? */
1918 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1919 printf("Partition %u has different physical/logical "
1920 "end:\n", partition + 1);
1921 printf(" phys=(%u,%u,%u) ", pec, peh, pes);
1922 printf("logical=(%u,%u,%u)\n", lec, leh, les);
1925 /* Ending on cylinder boundary? */
1926 if (peh != (g_heads - 1) || pes != g_sectors) {
1927 printf("Partition %u does not end on cylinder boundary\n",
1933 list_disk_geometry(void)
1935 ullong bytes = ((ullong)total_number_of_sectors << 9);
1936 ullong xbytes = bytes / (1024*1024);
1939 if (xbytes >= 10000) {
1940 xbytes += 512; /* fdisk util-linux 2.28 does this */
1944 printf("Disk %s: %llu %cB, %llu bytes, %"SECT_FMT"u sectors\n"
1945 "%u cylinders, %u heads, %u sectors/track\n"
1946 "Units: %s of %u * %u = %u bytes\n\n",
1947 disk_device, xbytes, x,
1948 bytes, total_number_of_sectors,
1949 g_cylinders, g_heads, g_sectors,
1951 units_per_sector, sector_size, units_per_sector * sector_size
1956 * Check whether partition entries are ordered by their starting positions.
1957 * Return 0 if OK. Return i if partition i should have been earlier.
1958 * Two separate checks: primary and logical partitions.
1961 wrong_p_order(int *prev)
1963 const struct pte *pe;
1964 const struct partition *p;
1965 sector_t last_p_start_pos = 0, p_start_pos;
1966 unsigned i, last_i = 0;
1968 for (i = 0; i < g_partitions; i++) {
1971 last_p_start_pos = 0;
1976 p_start_pos = get_partition_start_from_dev_start(pe);
1978 if (last_p_start_pos > p_start_pos) {
1984 last_p_start_pos = p_start_pos;
1991 #if ENABLE_FEATURE_FDISK_ADVANCED
1993 * Fix the chain of logicals.
1994 * extended_offset is unchanged, the set of sectors used is unchanged
1995 * The chain is sorted so that sectors increase, and so that
1996 * starting sectors increase.
1998 * After this it may still be that cfdisk doesnt like the table.
1999 * (This is because cfdisk considers expanded parts, from link to
2000 * end of partition, and these may still overlap.)
2002 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
2006 fix_chain_of_logicals(void)
2008 int j, oj, ojj, sj, sjj;
2009 struct partition *pj,*pjj,tmp;
2011 /* Stage 1: sort sectors but leave sector of part 4 */
2012 /* (Its sector is the global extended_offset.) */
2014 for (j = 5; j < g_partitions - 1; j++) {
2015 oj = ptes[j].offset_from_dev_start;
2016 ojj = ptes[j+1].offset_from_dev_start;
2018 ptes[j].offset_from_dev_start = ojj;
2019 ptes[j+1].offset_from_dev_start = oj;
2020 pj = ptes[j].part_table;
2021 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
2022 pjj = ptes[j+1].part_table;
2023 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
2024 set_start_sect(ptes[j-1].ext_pointer,
2025 ojj-extended_offset);
2026 set_start_sect(ptes[j].ext_pointer,
2027 oj-extended_offset);
2032 /* Stage 2: sort starting sectors */
2034 for (j = 4; j < g_partitions - 1; j++) {
2035 pj = ptes[j].part_table;
2036 pjj = ptes[j+1].part_table;
2037 sj = get_start_sect(pj);
2038 sjj = get_start_sect(pjj);
2039 oj = ptes[j].offset_from_dev_start;
2040 ojj = ptes[j+1].offset_from_dev_start;
2041 if (oj+sj > ojj+sjj) {
2045 set_start_sect(pj, ojj+sjj-oj);
2046 set_start_sect(pjj, oj+sj-ojj);
2051 /* Probably something was changed */
2052 for (j = 4; j < g_partitions; j++)
2053 ptes[j].changed = 1;
2058 fix_partition_table_order(void)
2060 struct pte *pei, *pek;
2063 if (!wrong_p_order(NULL)) {
2064 puts("Ordering is already correct\n");
2068 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2069 /* partition i should have come earlier, move it */
2070 /* We have to move data in the MBR */
2071 struct partition *pi, *pk, *pe, pbuf;
2075 pe = pei->ext_pointer;
2076 pei->ext_pointer = pek->ext_pointer;
2077 pek->ext_pointer = pe;
2079 pi = pei->part_table;
2080 pk = pek->part_table;
2082 memmove(&pbuf, pi, sizeof(struct partition));
2083 memmove(pi, pk, sizeof(struct partition));
2084 memmove(pk, &pbuf, sizeof(struct partition));
2086 pei->changed = pek->changed = 1;
2090 fix_chain_of_logicals();
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 */