1 /* vi: set sw=4 ts=4: */
2 /* fdisk.c -- Partition table manipulator for Linux.
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
10 #ifndef _LARGEFILE64_SOURCE
12 # define _LARGEFILE64_SOURCE
14 #include <assert.h> /* assert */
15 #include <sys/mount.h>
16 #if !defined(BLKSSZGET)
17 # define BLKSSZGET _IO(0x12, 104)
19 #if !defined(BLKGETSIZE64)
20 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
24 /* Looks like someone forgot to add this to config system */
25 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
26 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
27 # define IF_FEATURE_FDISK_BLKSIZE(a)
30 #define DEFAULT_SECTOR_SIZE 512
31 #define DEFAULT_SECTOR_SIZE_STR "512"
32 #define MAX_SECTOR_SIZE 2048
33 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
34 #define MAXIMUM_PARTS 60
36 #define ACTIVE_FLAG 0x80
39 #define WIN98_EXTENDED 0x0f
40 #define LINUX_PARTITION 0x81
41 #define LINUX_SWAP 0x82
42 #define LINUX_NATIVE 0x83
43 #define LINUX_EXTENDED 0x85
44 #define LINUX_LVM 0x8e
45 #define LINUX_RAID 0xfd
55 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
59 typedef unsigned long long ullong;
60 /* Used for sector numbers. Partition formats we know
61 * do not support more than 2^32 sectors
63 typedef uint32_t sector_t;
64 #if UINT_MAX == 4294967295
66 #elif ULONG_MAX == 4294967295
69 # error Cant detect sizeof(uint32_t)
74 unsigned char sectors;
75 unsigned short cylinders;
79 #define HDIO_GETGEO 0x0301 /* get device geometry */
81 static const char msg_building_new_label[] ALIGN1 =
82 "Building a new %s. Changes will remain in memory only,\n"
83 "until you decide to write them. After that the previous content\n"
84 "won't be recoverable.\n\n";
86 static const char msg_part_already_defined[] ALIGN1 =
87 "Partition %u is already defined, delete it before re-adding\n";
91 unsigned char boot_ind; /* 0x80 - active */
92 unsigned char head; /* starting head */
93 unsigned char sector; /* starting sector */
94 unsigned char cyl; /* starting cylinder */
95 unsigned char sys_ind; /* what partition type */
96 unsigned char end_head; /* end head */
97 unsigned char end_sector; /* end sector */
98 unsigned char end_cyl; /* end cylinder */
99 unsigned char start4[4]; /* starting sector counting from 0 */
100 unsigned char size4[4]; /* nr of sectors in partition */
103 static const char unable_to_open[] ALIGN1 = "can't open '%s'";
104 static const char unable_to_read[] ALIGN1 = "can't read from %s";
105 static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
108 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
111 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
113 #if ENABLE_FEATURE_SUN_LABEL
114 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
115 #define STATIC_SUN static
117 #define LABEL_IS_SUN 0
118 #define STATIC_SUN extern
121 #if ENABLE_FEATURE_SGI_LABEL
122 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
123 #define STATIC_SGI static
125 #define LABEL_IS_SGI 0
126 #define STATIC_SGI extern
129 #if ENABLE_FEATURE_AIX_LABEL
130 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
131 #define STATIC_AIX static
133 #define LABEL_IS_AIX 0
134 #define STATIC_AIX extern
137 #if ENABLE_FEATURE_OSF_LABEL
138 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
139 #define STATIC_OSF static
141 #define LABEL_IS_OSF 0
142 #define STATIC_OSF extern
145 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
147 static void update_units(void);
148 #if ENABLE_FEATURE_FDISK_WRITABLE
149 static void change_units(void);
150 static void reread_partition_table(int leave);
151 static void delete_partition(int i);
152 static unsigned get_partition(int warn, unsigned max);
153 static void list_types(const char *const *sys);
154 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
156 static const char *partition_type(unsigned char type);
157 static void get_geometry(void);
158 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
159 static int get_boot(enum action what);
161 static int get_boot(void);
167 static sector_t get_start_sect(const struct partition *p);
168 static sector_t get_nr_sects(const struct partition *p);
171 * per partition table entry data
173 * The four primary partitions have the same sectorbuffer (MBRbuffer)
174 * and have NULL ext_pointer.
175 * Each logical partition table entry has two pointers, one for the
176 * partition and one link to the next one.
179 struct partition *part_table; /* points into sectorbuffer */
180 struct partition *ext_pointer; /* points into sectorbuffer */
181 sector_t offset; /* disk sector number */
182 char *sectorbuffer; /* disk sector contents */
183 #if ENABLE_FEATURE_FDISK_WRITABLE
184 char changed; /* boolean */
188 /* DOS partition types */
190 static const char *const i386_sys_types[] = {
194 "\x05" "Extended", /* DOS 3.3+ extended partition */
195 "\x06" "FAT16", /* DOS 16-bit >=32M */
196 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
197 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
198 "\x0b" "Win95 FAT32",
199 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
200 "\x0e" "Win95 FAT16 (LBA)",
201 "\x0f" "Win95 Ext'd (LBA)",
202 "\x11" "Hidden FAT12",
203 "\x12" "Compaq diagnostics",
204 "\x14" "Hidden FAT16 <32M",
205 "\x16" "Hidden FAT16",
206 "\x17" "Hidden HPFS/NTFS",
207 "\x1b" "Hidden Win95 FAT32",
208 "\x1c" "Hidden W95 FAT32 (LBA)",
209 "\x1e" "Hidden W95 FAT16 (LBA)",
210 "\x3c" "Part.Magic recovery",
211 "\x41" "PPC PReP Boot",
213 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
214 "\x80" "Old Minix", /* Minix 1.4a and earlier */
215 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
216 "\x82" "Linux swap", /* also Solaris */
218 "\x84" "OS/2 hidden C: drive",
219 "\x85" "Linux extended",
220 "\x86" "NTFS volume set",
221 "\x87" "NTFS volume set",
223 "\x9f" "BSD/OS", /* BSDI */
224 "\xa0" "Thinkpad hibernation",
225 "\xa5" "FreeBSD", /* various BSD flavours */
229 "\xab" "Darwin boot",
232 "\xbe" "Solaris boot",
234 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
235 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
236 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
237 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
238 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
239 autodetect using persistent
241 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
244 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
245 "\x09" "AIX bootable", /* AIX data or Coherent */
247 "\x18" "AST SmartSleep",
250 "\x40" "Venix 80286",
252 "\x4e" "QNX4.x 2nd part",
253 "\x4f" "QNX4.x 3rd part",
255 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
256 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
257 "\x53" "OnTrack DM6 Aux3",
261 "\x5c" "Priam Edisk",
263 "\x64" "Novell Netware 286",
264 "\x65" "Novell Netware 386",
265 "\x70" "DiskSecure Multi-Boot",
268 "\x94" "Amoeba BBT", /* (bad block table) */
270 "\xbb" "Boot Wizard hidden",
271 "\xc1" "DRDOS/sec (FAT-12)",
272 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
273 "\xc6" "DRDOS/sec (FAT-16)",
275 "\xda" "Non-FS data",
276 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
277 Concurrent DOS or CTOS */
278 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
279 "\xdf" "BootIt", /* BootIt EMBRM */
280 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
281 extended partition */
282 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
283 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
284 partition < 1024 cyl. */
286 "\xf4" "SpeedStor", /* SpeedStor large partition */
287 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
288 "\xff" "BBT", /* Xenix Bad Block Table */
294 dev_fd = 3 /* the disk */
301 const char *disk_device;
302 int g_partitions; // = 4; /* maximum partition + 1 */
303 unsigned units_per_sector; // = 1;
304 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
305 unsigned user_set_sector_size;
306 unsigned sector_offset; // = 1;
307 unsigned g_heads, g_sectors, g_cylinders;
308 smallint /* enum label_type */ current_label_type;
309 smallint display_in_cyl_units; // = 1;
310 #if ENABLE_FEATURE_OSF_LABEL
311 smallint possibly_osf_label;
314 smallint listing; /* no aborts for fdisk -l */
315 smallint dos_compatible_flag; // = 1;
316 #if ENABLE_FEATURE_FDISK_WRITABLE
318 smallint nowarn; /* no warnings for fdisk -l/-s */
320 int ext_index; /* the prime extended partition */
321 unsigned user_cylinders, user_heads, user_sectors;
322 unsigned pt_heads, pt_sectors;
323 unsigned kern_heads, kern_sectors;
324 sector_t extended_offset; /* offset of link pointers */
325 sector_t total_number_of_sectors;
328 char line_buffer[80];
329 char partname_buffer[80];
330 /* Raw disk label. For DOS-type partition tables the MBR,
331 * with descriptions of the primary partitions. */
332 char MBRbuffer[MAX_SECTOR_SIZE];
333 /* Partition tables */
334 struct pte ptes[MAXIMUM_PARTS];
336 #define G (*ptr_to_globals)
337 #define line_ptr (G.line_ptr )
338 #define disk_device (G.disk_device )
339 #define g_partitions (G.g_partitions )
340 #define units_per_sector (G.units_per_sector )
341 #define sector_size (G.sector_size )
342 #define user_set_sector_size (G.user_set_sector_size)
343 #define sector_offset (G.sector_offset )
344 #define g_heads (G.g_heads )
345 #define g_sectors (G.g_sectors )
346 #define g_cylinders (G.g_cylinders )
347 #define current_label_type (G.current_label_type )
348 #define display_in_cyl_units (G.display_in_cyl_units)
349 #define possibly_osf_label (G.possibly_osf_label )
350 #define listing (G.listing )
351 #define dos_compatible_flag (G.dos_compatible_flag )
352 #define nowarn (G.nowarn )
353 #define ext_index (G.ext_index )
354 #define user_cylinders (G.user_cylinders )
355 #define user_heads (G.user_heads )
356 #define user_sectors (G.user_sectors )
357 #define pt_heads (G.pt_heads )
358 #define pt_sectors (G.pt_sectors )
359 #define kern_heads (G.kern_heads )
360 #define kern_sectors (G.kern_sectors )
361 #define extended_offset (G.extended_offset )
362 #define total_number_of_sectors (G.total_number_of_sectors)
363 #define listingbuf (G.listingbuf )
364 #define line_buffer (G.line_buffer )
365 #define partname_buffer (G.partname_buffer)
366 #define MBRbuffer (G.MBRbuffer )
367 #define ptes (G.ptes )
368 #define INIT_G() do { \
369 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
370 sector_size = DEFAULT_SECTOR_SIZE; \
373 display_in_cyl_units = 1; \
374 units_per_sector = 1; \
375 dos_compatible_flag = 1; \
379 /* TODO: move to libbb? */
380 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
381 * disks > 2^32 sectors
383 static sector_t bb_BLKGETSIZE_sectors(int fd)
386 unsigned long longsectors;
388 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
389 /* Got bytes, convert to 512 byte sectors */
391 if (v64 != (sector_t)v64) {
393 /* Not only DOS, but all other partition tables
394 * we support can't record more than 32 bit
395 * sector counts or offsets
397 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
402 /* Needs temp of type long */
403 if (ioctl(fd, BLKGETSIZE, &longsectors))
405 if (sizeof(long) > sizeof(sector_t)
406 && longsectors != (sector_t)longsectors
414 #define IS_EXTENDED(i) \
415 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
417 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
419 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
421 #define pt_offset(b, n) \
422 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
424 #define sector(s) ((s) & 0x3f)
426 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
428 #define hsc2sector(h,s,c) \
429 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
431 #define set_hsc(h,s,c,sector) \
433 s = sector % g_sectors + 1; \
434 sector /= g_sectors; \
435 h = sector % g_heads; \
438 s |= (sector >> 2) & 0xc0; \
444 /* Not really closing, but making sure it is open, and to harmless place */
445 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
448 #if ENABLE_FEATURE_FDISK_WRITABLE
449 /* Read line; return 0 or first printable char */
451 read_line(const char *prompt)
455 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
457 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
459 if (line_buffer[sz-1] == '\n')
460 line_buffer[--sz] = '\0';
462 line_ptr = line_buffer;
463 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
470 * Return partition name - uses static storage
473 partname(const char *dev, int pno, int lth)
480 bufp = partname_buffer;
481 bufsiz = sizeof(partname_buffer);
486 if (isdigit(dev[w-1]))
489 /* devfs kludge - note: fdisk partition names are not supposed
490 to equal kernel names, so there is no reason to do this */
491 if (strcmp(dev + w - 4, "disc") == 0) {
499 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
500 lth-wp-2, w, dev, p, pno);
502 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
507 #if ENABLE_FEATURE_FDISK_WRITABLE
509 set_all_unchanged(void)
513 for (i = 0; i < MAXIMUM_PARTS; i++)
517 static ALWAYS_INLINE void
522 #endif /* FEATURE_FDISK_WRITABLE */
524 static ALWAYS_INLINE struct partition *
525 get_part_table(int i)
527 return ptes[i].part_table;
532 { /* n==1: use singular */
534 return display_in_cyl_units ? "cylinder" : "sector";
535 return display_in_cyl_units ? "cylinders" : "sectors";
539 valid_part_table_flag(const char *mbuffer)
541 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
544 #if ENABLE_FEATURE_FDISK_WRITABLE
545 static ALWAYS_INLINE void
546 write_part_table_flag(char *b)
553 read_nonempty(const char *mesg)
555 while (!read_line(mesg))
561 read_maybe_empty(const char *mesg)
563 if (!read_line(mesg)) {
564 line_ptr = line_buffer;
572 read_hex(const char *const *sys)
576 read_nonempty("Hex code (type L to list codes): ");
577 if (*line_ptr == 'l' || *line_ptr == 'L') {
581 v = bb_strtoul(line_ptr, NULL, 16);
583 /* Bad input also triggers this */
588 #endif /* FEATURE_FDISK_WRITABLE */
590 static void fdisk_fatal(const char *why)
594 longjmp(listingbuf, 1);
596 bb_error_msg_and_die(why, disk_device);
600 seek_sector(sector_t secno)
602 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
603 off64_t off = (off64_t)secno * sector_size;
604 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
605 fdisk_fatal(unable_to_seek);
607 uint64_t off = (uint64_t)secno * sector_size;
608 if (off > MAXINT(off_t)
609 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
611 fdisk_fatal(unable_to_seek);
616 #if ENABLE_FEATURE_FDISK_WRITABLE
618 write_sector(sector_t secno, const void *buf)
621 xwrite(dev_fd, buf, sector_size);
626 #include "fdisk_aix.c"
628 struct sun_partition {
629 unsigned char info[128]; /* Informative text string */
630 unsigned char spare0[14];
632 unsigned char spare1;
634 unsigned char spare2;
637 unsigned char spare1[246]; /* Boot information etc. */
638 unsigned short rspeed; /* Disk rotational speed */
639 unsigned short pcylcount; /* Physical cylinder count */
640 unsigned short sparecyl; /* extra sects per cylinder */
641 unsigned char spare2[4]; /* More magic... */
642 unsigned short ilfact; /* Interleave factor */
643 unsigned short ncyl; /* Data cylinder count */
644 unsigned short nacyl; /* Alt. cylinder count */
645 unsigned short ntrks; /* Tracks per cylinder */
646 unsigned short nsect; /* Sectors per track */
647 unsigned char spare3[4]; /* Even more magic... */
648 struct sun_partinfo {
649 uint32_t start_cylinder;
650 uint32_t num_sectors;
652 unsigned short magic; /* Magic number */
653 unsigned short csum; /* Label xor'd checksum */
655 typedef struct sun_partition sun_partition;
656 #define sunlabel ((sun_partition *)MBRbuffer)
657 STATIC_OSF void bsd_select(void);
658 STATIC_OSF void xbsd_print_disklabel(int);
659 #include "fdisk_osf.c"
661 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
663 fdisk_swap16(uint16_t x)
665 return (x << 8) | (x >> 8);
669 fdisk_swap32(uint32_t x)
672 ((x & 0xFF00) << 8) |
673 ((x & 0xFF0000) >> 8) |
678 STATIC_SGI const char *const sgi_sys_types[];
679 STATIC_SGI unsigned sgi_get_num_sectors(int i);
680 STATIC_SGI int sgi_get_sysid(int i);
681 STATIC_SGI void sgi_delete_partition(int i);
682 STATIC_SGI void sgi_change_sysid(int i, int sys);
683 STATIC_SGI void sgi_list_table(int xtra);
684 #if ENABLE_FEATURE_FDISK_ADVANCED
685 STATIC_SGI void sgi_set_xcyl(void);
687 STATIC_SGI int verify_sgi(int verbose);
688 STATIC_SGI void sgi_add_partition(int n, int sys);
689 STATIC_SGI void sgi_set_swappartition(int i);
690 STATIC_SGI const char *sgi_get_bootfile(void);
691 STATIC_SGI void sgi_set_bootfile(const char* aFile);
692 STATIC_SGI void create_sgiinfo(void);
693 STATIC_SGI void sgi_write_table(void);
694 STATIC_SGI void sgi_set_bootpartition(int i);
695 #include "fdisk_sgi.c"
697 STATIC_SUN const char *const sun_sys_types[];
698 STATIC_SUN void sun_delete_partition(int i);
699 STATIC_SUN void sun_change_sysid(int i, int sys);
700 STATIC_SUN void sun_list_table(int xtra);
701 STATIC_SUN void add_sun_partition(int n, int sys);
702 #if ENABLE_FEATURE_FDISK_ADVANCED
703 STATIC_SUN void sun_set_alt_cyl(void);
704 STATIC_SUN void sun_set_ncyl(int cyl);
705 STATIC_SUN void sun_set_xcyl(void);
706 STATIC_SUN void sun_set_ilfact(void);
707 STATIC_SUN void sun_set_rspeed(void);
708 STATIC_SUN void sun_set_pcylcount(void);
710 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
711 STATIC_SUN void verify_sun(void);
712 STATIC_SUN void sun_write_table(void);
713 #include "fdisk_sun.c"
716 #if ENABLE_FEATURE_FDISK_WRITABLE
717 /* start_sect and nr_sects are stored little endian on all machines */
718 /* moreover, they are not aligned correctly */
720 store4_little_endian(unsigned char *cp, unsigned val)
727 #endif /* FEATURE_FDISK_WRITABLE */
730 read4_little_endian(const unsigned char *cp)
732 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
735 #if ENABLE_FEATURE_FDISK_WRITABLE
737 set_start_sect(struct partition *p, unsigned start_sect)
739 store4_little_endian(p->start4, start_sect);
744 get_start_sect(const struct partition *p)
746 return read4_little_endian(p->start4);
749 #if ENABLE_FEATURE_FDISK_WRITABLE
751 set_nr_sects(struct partition *p, unsigned nr_sects)
753 store4_little_endian(p->size4, nr_sects);
758 get_nr_sects(const struct partition *p)
760 return read4_little_endian(p->size4);
763 /* Allocate a buffer and read a partition table sector */
765 read_pte(struct pte *pe, sector_t offset)
768 pe->sectorbuffer = xzalloc(sector_size);
770 /* xread would make us abort - bad for fdisk -l */
771 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
772 fdisk_fatal(unable_to_read);
773 #if ENABLE_FEATURE_FDISK_WRITABLE
776 pe->part_table = pe->ext_pointer = NULL;
780 get_partition_start(const struct pte *pe)
782 return pe->offset + get_start_sect(pe->part_table);
785 #if ENABLE_FEATURE_FDISK_WRITABLE
787 * Avoid warning about DOS partitions when no DOS partition was changed.
788 * Here a heuristic "is probably dos partition".
789 * We might also do the opposite and warn in all cases except
790 * for "is probably nondos partition".
794 is_dos_partition(int t)
796 return (t == 1 || t == 4 || t == 6 ||
797 t == 0x0b || t == 0x0c || t == 0x0e ||
798 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
799 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
800 t == 0xc1 || t == 0xc4 || t == 0xc6);
807 puts("Command Action");
809 puts("a\ttoggle a read only flag"); /* sun */
810 puts("b\tedit bsd disklabel");
811 puts("c\ttoggle the mountable flag"); /* sun */
812 puts("d\tdelete a partition");
813 puts("l\tlist known partition types");
814 puts("n\tadd a new partition");
815 puts("o\tcreate a new empty DOS partition table");
816 puts("p\tprint the partition table");
817 puts("q\tquit without saving changes");
818 puts("s\tcreate a new empty Sun disklabel"); /* sun */
819 puts("t\tchange a partition's system id");
820 puts("u\tchange display/entry units");
821 puts("v\tverify the partition table");
822 puts("w\twrite table to disk and exit");
823 #if ENABLE_FEATURE_FDISK_ADVANCED
824 puts("x\textra functionality (experts only)");
826 } else if (LABEL_IS_SGI) {
827 puts("a\tselect bootable partition"); /* sgi flavour */
828 puts("b\tedit bootfile entry"); /* sgi */
829 puts("c\tselect sgi swap partition"); /* sgi flavour */
830 puts("d\tdelete a partition");
831 puts("l\tlist known partition types");
832 puts("n\tadd a new partition");
833 puts("o\tcreate a new empty DOS partition table");
834 puts("p\tprint the partition table");
835 puts("q\tquit without saving changes");
836 puts("s\tcreate a new empty Sun disklabel"); /* sun */
837 puts("t\tchange a partition's system id");
838 puts("u\tchange display/entry units");
839 puts("v\tverify the partition table");
840 puts("w\twrite table to disk and exit");
841 } else if (LABEL_IS_AIX) {
842 puts("o\tcreate a new empty DOS partition table");
843 puts("q\tquit without saving changes");
844 puts("s\tcreate a new empty Sun disklabel"); /* sun */
846 puts("a\ttoggle a bootable flag");
847 puts("b\tedit bsd disklabel");
848 puts("c\ttoggle the dos compatibility flag");
849 puts("d\tdelete a partition");
850 puts("l\tlist known partition types");
851 puts("n\tadd a new partition");
852 puts("o\tcreate a new empty DOS partition table");
853 puts("p\tprint the partition table");
854 puts("q\tquit without saving changes");
855 puts("s\tcreate a new empty Sun disklabel"); /* sun */
856 puts("t\tchange a partition's system id");
857 puts("u\tchange display/entry units");
858 puts("v\tverify the partition table");
859 puts("w\twrite table to disk and exit");
860 #if ENABLE_FEATURE_FDISK_ADVANCED
861 puts("x\textra functionality (experts only)");
865 #endif /* FEATURE_FDISK_WRITABLE */
868 #if ENABLE_FEATURE_FDISK_ADVANCED
872 puts("Command Action");
874 puts("a\tchange number of alternate cylinders"); /*sun*/
875 puts("c\tchange number of cylinders");
876 puts("d\tprint the raw data in the partition table");
877 puts("e\tchange number of extra sectors per cylinder");/*sun*/
878 puts("h\tchange number of heads");
879 puts("i\tchange interleave factor"); /*sun*/
880 puts("o\tchange rotation speed (rpm)"); /*sun*/
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 puts("y\tchange number of physical cylinders"); /*sun*/
888 } else if (LABEL_IS_SGI) {
889 puts("b\tmove beginning of data in a partition"); /* !sun */
890 puts("c\tchange number of cylinders");
891 puts("d\tprint the raw data in the partition table");
892 puts("e\tlist extended partitions"); /* !sun */
893 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
894 puts("h\tchange number of heads");
895 puts("p\tprint the partition table");
896 puts("q\tquit without saving changes");
897 puts("r\treturn to main menu");
898 puts("s\tchange number of sectors/track");
899 puts("v\tverify the partition table");
900 puts("w\twrite table to disk and exit");
901 } else if (LABEL_IS_AIX) {
902 puts("b\tmove beginning of data in a partition"); /* !sun */
903 puts("c\tchange number of cylinders");
904 puts("d\tprint the raw data in the partition table");
905 puts("e\tlist extended partitions"); /* !sun */
906 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
907 puts("h\tchange number of heads");
908 puts("p\tprint the partition table");
909 puts("q\tquit without saving changes");
910 puts("r\treturn to main menu");
911 puts("s\tchange number of sectors/track");
912 puts("v\tverify the partition table");
913 puts("w\twrite table to disk and exit");
915 puts("b\tmove beginning of data in a partition"); /* !sun */
916 puts("c\tchange number of cylinders");
917 puts("d\tprint the raw data in the partition table");
918 puts("e\tlist extended partitions"); /* !sun */
919 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
920 #if ENABLE_FEATURE_SGI_LABEL
921 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
923 puts("h\tchange number of heads");
924 puts("p\tprint the partition table");
925 puts("q\tquit without saving changes");
926 puts("r\treturn to main menu");
927 puts("s\tchange number of sectors/track");
928 puts("v\tverify the partition table");
929 puts("w\twrite table to disk and exit");
932 #endif /* ADVANCED mode */
934 #if ENABLE_FEATURE_FDISK_WRITABLE
935 static const char *const *
939 LABEL_IS_SUN ? sun_sys_types :
940 LABEL_IS_SGI ? sgi_sys_types :
944 #define get_sys_types() i386_sys_types
945 #endif /* FEATURE_FDISK_WRITABLE */
948 partition_type(unsigned char type)
951 const char *const *types = get_sys_types();
953 for (i = 0; types[i]; i++)
954 if ((unsigned char)types[i][0] == type)
961 #if ENABLE_FEATURE_FDISK_WRITABLE
965 return LABEL_IS_SUN ? sunlabel->infos[i].id :
966 (LABEL_IS_SGI ? sgi_get_sysid(i) :
967 ptes[i].part_table->sys_ind);
971 list_types(const char *const *sys)
976 unsigned done, next, size;
979 for (size = 0; sys[size]; size++)
983 for (i = COLS-1; i >= 0; i--) {
984 done += (size + i - done) / (i + 1);
985 last[COLS-1 - i] = done;
990 printf("%c%2x %-22.22s", i ? ' ' : '\n',
991 (unsigned char)sys[next][0],
993 next = last[i++] + done;
994 if (i >= COLS || next >= last[i]) {
998 } while (done < last[0]);
1001 #endif /* FEATURE_FDISK_WRITABLE */
1004 is_cleared_partition(const struct partition *p)
1006 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
1007 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
1008 get_start_sect(p) || get_nr_sects(p));
1012 clear_partition(struct partition *p)
1016 memset(p, 0, sizeof(struct partition));
1019 #if ENABLE_FEATURE_FDISK_WRITABLE
1021 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1023 struct partition *p;
1027 p = ptes[i].ext_pointer;
1028 offset = extended_offset;
1030 p = ptes[i].part_table;
1031 offset = ptes[i].offset;
1035 set_start_sect(p, start - offset);
1036 set_nr_sects(p, stop - start + 1);
1037 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1038 start = g_heads * g_sectors * 1024 - 1;
1039 set_hsc(p->head, p->sector, p->cyl, start);
1040 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1041 stop = g_heads * g_sectors * 1024 - 1;
1042 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1043 ptes[i].changed = 1;
1050 if (g_heads && g_sectors && g_cylinders)
1053 printf("Unknown value(s) for:");
1059 printf(" cylinders");
1061 #if ENABLE_FEATURE_FDISK_WRITABLE
1062 " (settable in the extra functions menu)"
1071 int cyl_units = g_heads * g_sectors;
1073 if (display_in_cyl_units && cyl_units)
1074 units_per_sector = cyl_units;
1076 units_per_sector = 1; /* in sectors */
1079 #if ENABLE_FEATURE_FDISK_WRITABLE
1081 warn_cylinders(void)
1083 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1085 "The number of cylinders for this disk is set to %u.\n"
1086 "There is nothing wrong with that, but this is larger than 1024,\n"
1087 "and could in certain setups cause problems with:\n"
1088 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1089 "2) booting and partitioning software from other OSs\n"
1090 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1096 read_extended(int ext)
1100 struct partition *p, *q;
1104 pex->ext_pointer = pex->part_table;
1106 p = pex->part_table;
1107 if (!get_start_sect(p)) {
1108 printf("Bad offset in primary extended partition\n");
1112 while (IS_EXTENDED(p->sys_ind)) {
1113 struct pte *pe = &ptes[g_partitions];
1115 if (g_partitions >= MAXIMUM_PARTS) {
1116 /* This is not a Linux restriction, but
1117 this program uses arrays of size MAXIMUM_PARTS.
1118 Do not try to 'improve' this test. */
1119 struct pte *pre = &ptes[g_partitions - 1];
1120 #if ENABLE_FEATURE_FDISK_WRITABLE
1121 printf("Warning: deleting partitions after %u\n",
1125 clear_partition(pre->ext_pointer);
1129 read_pte(pe, extended_offset + get_start_sect(p));
1131 if (!extended_offset)
1132 extended_offset = get_start_sect(p);
1134 q = p = pt_offset(pe->sectorbuffer, 0);
1135 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1136 if (IS_EXTENDED(p->sys_ind)) {
1137 if (pe->ext_pointer)
1138 printf("Warning: extra link "
1139 "pointer in partition table"
1140 " %u\n", g_partitions + 1);
1142 pe->ext_pointer = p;
1143 } else if (p->sys_ind) {
1145 printf("Warning: ignoring extra "
1146 "data in partition table"
1147 " %u\n", g_partitions + 1);
1153 /* very strange code here... */
1154 if (!pe->part_table) {
1155 if (q != pe->ext_pointer)
1158 pe->part_table = q + 1;
1160 if (!pe->ext_pointer) {
1161 if (q != pe->part_table)
1162 pe->ext_pointer = q;
1164 pe->ext_pointer = q + 1;
1167 p = pe->ext_pointer;
1171 #if ENABLE_FEATURE_FDISK_WRITABLE
1172 /* remove empty links */
1174 for (i = 4; i < g_partitions; i++) {
1175 struct pte *pe = &ptes[i];
1177 if (!get_nr_sects(pe->part_table)
1178 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1180 printf("Omitting empty partition (%u)\n", i+1);
1181 delete_partition(i);
1182 goto remove; /* numbering changed */
1188 #if ENABLE_FEATURE_FDISK_WRITABLE
1190 create_doslabel(void)
1194 printf(msg_building_new_label, "DOS disklabel");
1196 current_label_type = LABEL_DOS;
1198 #if ENABLE_FEATURE_OSF_LABEL
1199 possibly_osf_label = 0;
1203 for (i = 510-64; i < 510; i++)
1205 write_part_table_flag(MBRbuffer);
1206 extended_offset = 0;
1207 set_all_unchanged();
1209 get_boot(CREATE_EMPTY_DOS);
1211 #endif /* FEATURE_FDISK_WRITABLE */
1214 get_sectorsize(void)
1216 if (!user_set_sector_size) {
1218 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1220 if (sector_size != DEFAULT_SECTOR_SIZE)
1221 printf("Note: sector size is %u "
1222 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1228 get_kernel_geometry(void)
1230 struct hd_geometry geometry;
1232 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1233 kern_heads = geometry.heads;
1234 kern_sectors = geometry.sectors;
1235 /* never use geometry.cylinders - it is truncated */
1240 get_partition_table_geometry(void)
1242 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1243 struct partition *p;
1244 int i, h, s, hh, ss;
1248 if (!(valid_part_table_flag((char*)bufp)))
1252 for (i = 0; i < 4; i++) {
1253 p = pt_offset(bufp, i);
1254 if (p->sys_ind != 0) {
1255 h = p->end_head + 1;
1256 s = (p->end_sector & 077);
1261 } else if (hh != h || ss != s)
1266 if (!first && !bad) {
1278 sec_fac = sector_size / 512;
1279 #if ENABLE_FEATURE_SUN_LABEL
1280 guess_device_type();
1282 g_heads = g_cylinders = g_sectors = 0;
1283 kern_heads = kern_sectors = 0;
1284 pt_heads = pt_sectors = 0;
1286 get_kernel_geometry();
1287 get_partition_table_geometry();
1289 g_heads = user_heads ? user_heads :
1290 pt_heads ? pt_heads :
1291 kern_heads ? kern_heads : 255;
1292 g_sectors = user_sectors ? user_sectors :
1293 pt_sectors ? pt_sectors :
1294 kern_sectors ? kern_sectors : 63;
1295 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1298 if (dos_compatible_flag)
1299 sector_offset = g_sectors;
1301 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1303 g_cylinders = user_cylinders;
1307 * Opens disk_device and optionally reads MBR.
1308 * FIXME: document what each 'what' value will do!
1310 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1311 * 0: found or created label
1314 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1315 static int get_boot(enum action what)
1317 static int get_boot(void)
1318 #define get_boot(what) get_boot()
1324 for (i = 0; i < 4; i++) {
1325 struct pte *pe = &ptes[i];
1326 pe->part_table = pt_offset(MBRbuffer, i);
1327 pe->ext_pointer = NULL;
1329 pe->sectorbuffer = MBRbuffer;
1330 #if ENABLE_FEATURE_FDISK_WRITABLE
1331 pe->changed = (what == CREATE_EMPTY_DOS);
1335 #if ENABLE_FEATURE_FDISK_WRITABLE
1336 // ALERT! highly idiotic design!
1337 // We end up here when we call get_boot() recursively
1338 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1339 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1340 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1341 // So skip opening device _again_...
1342 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1345 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1348 fd = open(disk_device, O_RDONLY);
1350 if (what == TRY_ONLY)
1352 fdisk_fatal(unable_to_open);
1354 printf("'%s' is opened for read only\n", disk_device);
1356 xmove_fd(fd, dev_fd);
1357 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1358 if (what == TRY_ONLY) {
1362 fdisk_fatal(unable_to_read);
1365 fd = open(disk_device, O_RDONLY);
1368 if (512 != full_read(fd, MBRbuffer, 512)) {
1372 xmove_fd(fd, dev_fd);
1378 #if ENABLE_FEATURE_SUN_LABEL
1379 if (check_sun_label())
1382 #if ENABLE_FEATURE_SGI_LABEL
1383 if (check_sgi_label())
1386 #if ENABLE_FEATURE_AIX_LABEL
1387 if (check_aix_label())
1390 #if ENABLE_FEATURE_OSF_LABEL
1391 if (check_osf_label()) {
1392 possibly_osf_label = 1;
1393 if (!valid_part_table_flag(MBRbuffer)) {
1394 current_label_type = LABEL_OSF;
1397 printf("This disk has both DOS and BSD magic.\n"
1398 "Give the 'b' command to go to BSD mode.\n");
1402 #if !ENABLE_FEATURE_FDISK_WRITABLE
1403 if (!valid_part_table_flag(MBRbuffer))
1406 if (!valid_part_table_flag(MBRbuffer)) {
1407 if (what == OPEN_MAIN) {
1408 printf("Device contains neither a valid DOS "
1409 "partition table, nor Sun, SGI or OSF "
1412 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1422 #endif /* FEATURE_FDISK_WRITABLE */
1425 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1428 for (i = 0; i < 4; i++) {
1429 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1430 if (g_partitions != 4)
1431 printf("Ignoring extra extended "
1432 "partition %u\n", i + 1);
1438 for (i = 3; i < g_partitions; i++) {
1439 struct pte *pe = &ptes[i];
1440 if (!valid_part_table_flag(pe->sectorbuffer)) {
1441 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1442 "table %u will be corrected by w(rite)\n",
1443 pe->sectorbuffer[510],
1444 pe->sectorbuffer[511],
1446 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1453 #if ENABLE_FEATURE_FDISK_WRITABLE
1455 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1456 * If the user hits Enter, DFLT is returned.
1457 * Answers like +10 are interpreted as offsets from BASE.
1459 * There is no default if DFLT is not between LOW and HIGH.
1462 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1466 const char *fmt = "%s (%u-%u, default %u): ";
1468 if (dflt < low || dflt > high) {
1469 fmt = "%s (%u-%u): ";
1474 int use_default = default_ok;
1476 /* ask question and read answer */
1478 printf(fmt, mesg, low, high, dflt);
1479 read_maybe_empty("");
1480 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1481 && *line_ptr != '-' && *line_ptr != '+');
1483 if (*line_ptr == '+' || *line_ptr == '-') {
1484 int minus = (*line_ptr == '-');
1487 value = atoi(line_ptr + 1);
1489 /* (1) if 2nd char is digit, use_default = 0.
1490 * (2) move line_ptr to first non-digit. */
1491 while (isdigit(*++line_ptr))
1494 switch (*line_ptr) {
1497 if (!display_in_cyl_units)
1498 value *= g_heads * g_sectors;
1512 absolute = 1000000000;
1521 bytes = (ullong) value * absolute;
1522 unit = sector_size * units_per_sector;
1523 bytes += unit/2; /* round */
1531 value = atoi(line_ptr);
1532 while (isdigit(*line_ptr)) {
1539 printf("Using default value %u\n", value);
1541 if (value >= low && value <= high)
1543 printf("Value is out of range\n");
1549 get_partition(int warn, unsigned max)
1554 i = read_int(1, 0, max, 0, "Partition number") - 1;
1558 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1559 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1560 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1562 printf("Warning: partition %u has empty type\n", i+1);
1569 get_existing_partition(int warn, unsigned max)
1574 for (i = 0; i < max; i++) {
1575 struct pte *pe = &ptes[i];
1576 struct partition *p = pe->part_table;
1578 if (p && !is_cleared_partition(p)) {
1585 printf("Selected partition %u\n", pno+1);
1588 printf("No partition is defined yet!\n");
1592 return get_partition(warn, max);
1596 get_nonexisting_partition(int warn, unsigned max)
1601 for (i = 0; i < max; i++) {
1602 struct pte *pe = &ptes[i];
1603 struct partition *p = pe->part_table;
1605 if (p && is_cleared_partition(p)) {
1612 printf("Selected partition %u\n", pno+1);
1615 printf("All primary partitions have been defined already!\n");
1619 return get_partition(warn, max);
1626 display_in_cyl_units = !display_in_cyl_units;
1628 printf("Changing display/entry units to %s\n",
1633 toggle_active(int i)
1635 struct pte *pe = &ptes[i];
1636 struct partition *p = pe->part_table;
1638 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1639 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1640 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1645 toggle_dos_compatibility_flag(void)
1647 dos_compatible_flag = 1 - dos_compatible_flag;
1648 if (dos_compatible_flag) {
1649 sector_offset = g_sectors;
1650 printf("DOS Compatibility flag is set\n");
1653 printf("DOS Compatibility flag is not set\n");
1658 delete_partition(int i)
1660 struct pte *pe = &ptes[i];
1661 struct partition *p = pe->part_table;
1662 struct partition *q = pe->ext_pointer;
1664 /* Note that for the fifth partition (i == 4) we don't actually
1665 * decrement partitions.
1668 if (warn_geometry())
1669 return; /* C/H/S not set */
1673 sun_delete_partition(i);
1677 sgi_delete_partition(i);
1682 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1684 ptes[ext_index].ext_pointer = NULL;
1685 extended_offset = 0;
1691 if (!q->sys_ind && i > 4) {
1692 /* the last one in the chain - just delete */
1695 clear_partition(ptes[i].ext_pointer);
1696 ptes[i].changed = 1;
1698 /* not the last one - further ones will be moved down */
1700 /* delete this link in the chain */
1701 p = ptes[i-1].ext_pointer;
1703 set_start_sect(p, get_start_sect(q));
1704 set_nr_sects(p, get_nr_sects(q));
1705 ptes[i-1].changed = 1;
1706 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1707 /* the first logical in a longer chain */
1710 if (pe->part_table) /* prevent SEGFAULT */
1711 set_start_sect(pe->part_table,
1712 get_partition_start(pe) -
1714 pe->offset = extended_offset;
1718 if (g_partitions > 5) {
1720 while (i < g_partitions) {
1721 ptes[i] = ptes[i+1];
1725 /* the only logical: clear only */
1726 clear_partition(ptes[i].part_table);
1733 int i, sys, origsys;
1734 struct partition *p;
1736 /* If sgi_label then don't use get_existing_partition,
1737 let the user select a partition, since get_existing_partition()
1738 only works for Linux like partition tables. */
1739 if (!LABEL_IS_SGI) {
1740 i = get_existing_partition(0, g_partitions);
1742 i = get_partition(0, g_partitions);
1746 p = ptes[i].part_table;
1747 origsys = sys = get_sysid(i);
1749 /* if changing types T to 0 is allowed, then
1750 the reverse change must be allowed, too */
1751 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1752 printf("Partition %u does not exist yet!\n", i + 1);
1756 sys = read_hex(get_sys_types());
1758 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1759 printf("Type 0 means free space to many systems\n"
1760 "(but not to Linux). Having partitions of\n"
1761 "type 0 is probably unwise.\n");
1765 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1766 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1767 printf("You cannot change a partition into"
1768 " an extended one or vice versa\n");
1774 #if ENABLE_FEATURE_SUN_LABEL
1775 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1776 printf("Consider leaving partition 3 "
1777 "as Whole disk (5),\n"
1778 "as SunOS/Solaris expects it and "
1779 "even Linux likes it\n\n");
1781 #if ENABLE_FEATURE_SGI_LABEL
1784 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1785 (i == 8 && sys != 0)
1788 printf("Consider leaving partition 9 "
1789 "as volume header (0),\nand "
1790 "partition 11 as entire volume (6)"
1791 "as IRIX expects it\n\n");
1797 sun_change_sysid(i, sys);
1798 } else if (LABEL_IS_SGI) {
1799 sgi_change_sysid(i, sys);
1803 printf("Changed system type of partition %u "
1804 "to %x (%s)\n", i + 1, sys,
1805 partition_type(sys));
1806 ptes[i].changed = 1;
1807 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1813 #endif /* FEATURE_FDISK_WRITABLE */
1816 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1817 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1818 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1819 * Lubkin Oct. 1991). */
1822 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1824 int spc = g_heads * g_sectors;
1828 *h = ls / g_sectors;
1829 *s = ls % g_sectors + 1; /* sectors count from 1 */
1833 check_consistency(const struct partition *p, int partition)
1835 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1836 unsigned pec, peh, pes; /* physical ending c, h, s */
1837 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1838 unsigned lec, leh, les; /* logical ending c, h, s */
1840 if (!g_heads || !g_sectors || (partition >= 4))
1841 return; /* do not check extended partitions */
1843 /* physical beginning c, h, s */
1844 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1846 pbs = p->sector & 0x3f;
1848 /* physical ending c, h, s */
1849 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1851 pes = p->end_sector & 0x3f;
1853 /* compute logical beginning (c, h, s) */
1854 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1856 /* compute logical ending (c, h, s) */
1857 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1859 /* Same physical / logical beginning? */
1860 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1861 printf("Partition %u has different physical/logical "
1862 "beginnings (non-Linux?):\n", partition + 1);
1863 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
1864 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
1867 /* Same physical / logical ending? */
1868 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1869 printf("Partition %u has different physical/logical "
1870 "endings:\n", partition + 1);
1871 printf(" phys=(%u, %u, %u) ", pec, peh, pes);
1872 printf("logical=(%u, %u, %u)\n", lec, leh, les);
1875 /* Ending on cylinder boundary? */
1876 if (peh != (g_heads - 1) || pes != g_sectors) {
1877 printf("Partition %u does not end on cylinder boundary\n",
1883 list_disk_geometry(void)
1885 ullong bytes = ((ullong)total_number_of_sectors << 9);
1886 long megabytes = bytes / 1000000;
1888 if (megabytes < 10000)
1889 printf("\nDisk %s: %lu MB, %llu bytes\n",
1890 disk_device, megabytes, bytes);
1892 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1893 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1894 printf("%u heads, %u sectors/track, %u cylinders",
1895 g_heads, g_sectors, g_cylinders);
1896 if (units_per_sector == 1)
1897 printf(", total %"SECT_FMT"u sectors",
1898 total_number_of_sectors / (sector_size/512));
1899 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1901 units_per_sector, sector_size, units_per_sector * sector_size);
1905 * Check whether partition entries are ordered by their starting positions.
1906 * Return 0 if OK. Return i if partition i should have been earlier.
1907 * Two separate checks: primary and logical partitions.
1910 wrong_p_order(int *prev)
1912 const struct pte *pe;
1913 const struct partition *p;
1914 sector_t last_p_start_pos = 0, p_start_pos;
1915 unsigned i, last_i = 0;
1917 for (i = 0; i < g_partitions; i++) {
1920 last_p_start_pos = 0;
1925 p_start_pos = get_partition_start(pe);
1927 if (last_p_start_pos > p_start_pos) {
1933 last_p_start_pos = p_start_pos;
1940 #if ENABLE_FEATURE_FDISK_ADVANCED
1942 * Fix the chain of logicals.
1943 * extended_offset is unchanged, the set of sectors used is unchanged
1944 * The chain is sorted so that sectors increase, and so that
1945 * starting sectors increase.
1947 * After this it may still be that cfdisk doesnt like the table.
1948 * (This is because cfdisk considers expanded parts, from link to
1949 * end of partition, and these may still overlap.)
1951 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1955 fix_chain_of_logicals(void)
1957 int j, oj, ojj, sj, sjj;
1958 struct partition *pj,*pjj,tmp;
1960 /* Stage 1: sort sectors but leave sector of part 4 */
1961 /* (Its sector is the global extended_offset.) */
1963 for (j = 5; j < g_partitions - 1; j++) {
1964 oj = ptes[j].offset;
1965 ojj = ptes[j+1].offset;
1967 ptes[j].offset = ojj;
1968 ptes[j+1].offset = oj;
1969 pj = ptes[j].part_table;
1970 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1971 pjj = ptes[j+1].part_table;
1972 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1973 set_start_sect(ptes[j-1].ext_pointer,
1974 ojj-extended_offset);
1975 set_start_sect(ptes[j].ext_pointer,
1976 oj-extended_offset);
1981 /* Stage 2: sort starting sectors */
1983 for (j = 4; j < g_partitions - 1; j++) {
1984 pj = ptes[j].part_table;
1985 pjj = ptes[j+1].part_table;
1986 sj = get_start_sect(pj);
1987 sjj = get_start_sect(pjj);
1988 oj = ptes[j].offset;
1989 ojj = ptes[j+1].offset;
1990 if (oj+sj > ojj+sjj) {
1994 set_start_sect(pj, ojj+sjj-oj);
1995 set_start_sect(pjj, oj+sj-ojj);
2000 /* Probably something was changed */
2001 for (j = 4; j < g_partitions; j++)
2002 ptes[j].changed = 1;
2007 fix_partition_table_order(void)
2009 struct pte *pei, *pek;
2012 if (!wrong_p_order(NULL)) {
2013 printf("Ordering is already correct\n\n");
2017 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2018 /* partition i should have come earlier, move it */
2019 /* We have to move data in the MBR */
2020 struct partition *pi, *pk, *pe, pbuf;
2024 pe = pei->ext_pointer;
2025 pei->ext_pointer = pek->ext_pointer;
2026 pek->ext_pointer = pe;
2028 pi = pei->part_table;
2029 pk = pek->part_table;
2031 memmove(&pbuf, pi, sizeof(struct partition));
2032 memmove(pi, pk, sizeof(struct partition));
2033 memmove(pk, &pbuf, sizeof(struct partition));
2035 pei->changed = pek->changed = 1;
2039 fix_chain_of_logicals();
2047 list_table(int xtra)
2049 const struct partition *p;
2053 sun_list_table(xtra);
2057 sgi_list_table(xtra);
2061 list_disk_geometry();
2064 xbsd_print_disklabel(xtra);
2068 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2069 but if the device name ends in a digit, say /dev/foo1,
2070 then the partition is called /dev/foo1p3. */
2071 w = strlen(disk_device);
2072 if (w && isdigit(disk_device[w-1]))
2077 // 1 12345678901 12345678901 12345678901 12
2078 printf("%*s Boot Start End Blocks Id System\n",
2081 for (i = 0; i < g_partitions; i++) {
2082 const struct pte *pe = &ptes[i];
2088 if (!p || is_cleared_partition(p))
2091 psects = get_nr_sects(p);
2095 if (sector_size < 1024) {
2096 pblocks /= (1024 / sector_size);
2097 podd = psects % (1024 / sector_size);
2099 if (sector_size > 1024)
2100 pblocks *= (sector_size / 1024);
2102 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
2103 partname(disk_device, i+1, w+2),
2104 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2106 cround(get_partition_start(pe)), /* start */
2107 cround(get_partition_start(pe) + psects /* end */
2108 - (psects ? 1 : 0)),
2109 pblocks, podd ? '+' : ' ', /* odd flag on end */
2110 p->sys_ind, /* type id */
2111 partition_type(p->sys_ind)); /* type name */
2113 check_consistency(p, i);
2116 /* Is partition table in disk order? It need not be, but... */
2117 /* partition table entries are not checked for correct order
2118 * if this is a sgi, sun or aix labeled disk... */
2119 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2121 printf("\nPartition table entries are not in disk order\n");
2125 #if ENABLE_FEATURE_FDISK_ADVANCED
2127 x_list_table(int extend)
2129 const struct pte *pe;
2130 const struct partition *p;
2133 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2134 disk_device, g_heads, g_sectors, g_cylinders);
2135 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2136 for (i = 0; i < g_partitions; i++) {
2138 p = (extend ? pe->ext_pointer : pe->part_table);
2140 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2141 i + 1, p->boot_ind, p->head,
2143 cylinder(p->sector, p->cyl), p->end_head,
2144 sector(p->end_sector),
2145 cylinder(p->end_sector, p->end_cyl),
2146 get_start_sect(p), get_nr_sects(p),
2149 check_consistency(p, i);
2155 #if ENABLE_FEATURE_FDISK_WRITABLE
2157 fill_bounds(sector_t *first, sector_t *last)
2160 const struct pte *pe = &ptes[0];
2161 const struct partition *p;
2163 for (i = 0; i < g_partitions; pe++,i++) {
2165 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2166 first[i] = 0xffffffff;
2169 first[i] = get_partition_start(pe);
2170 last[i] = first[i] + get_nr_sects(p) - 1;
2176 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2178 sector_t total, real_s, real_c;
2180 real_s = sector(s) - 1;
2181 real_c = cylinder(s, c);
2182 total = (real_c * g_sectors + real_s) * g_heads + h;
2184 printf("Partition %u contains sector 0\n", n);
2186 printf("Partition %u: head %u greater than maximum %u\n",
2188 if (real_s >= g_sectors)
2189 printf("Partition %u: sector %u greater than "
2190 "maximum %u\n", n, s, g_sectors);
2191 if (real_c >= g_cylinders)
2192 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2193 "maximum %u\n", n, real_c + 1, g_cylinders);
2194 if (g_cylinders <= 1024 && start != total)
2195 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2196 "total %"SECT_FMT"u\n", n, start, total);
2204 sector_t first[g_partitions], last[g_partitions];
2205 struct partition *p;
2207 if (warn_geometry())
2219 fill_bounds(first, last);
2220 for (i = 0; i < g_partitions; i++) {
2221 struct pte *pe = &ptes[i];
2224 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2225 check_consistency(p, i);
2226 if (get_partition_start(pe) < first[i])
2227 printf("Warning: bad start-of-data in "
2228 "partition %u\n", i + 1);
2229 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2231 total += last[i] + 1 - first[i];
2232 for (j = 0; j < i; j++) {
2233 if ((first[i] >= first[j] && first[i] <= last[j])
2234 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2235 printf("Warning: partition %u overlaps "
2236 "partition %u\n", j + 1, i + 1);
2237 total += first[i] >= first[j] ?
2238 first[i] : first[j];
2239 total -= last[i] <= last[j] ?
2246 if (extended_offset) {
2247 struct pte *pex = &ptes[ext_index];
2248 sector_t e_last = get_start_sect(pex->part_table) +
2249 get_nr_sects(pex->part_table) - 1;
2251 for (i = 4; i < g_partitions; i++) {
2253 p = ptes[i].part_table;
2255 if (i != 4 || i + 1 < g_partitions)
2256 printf("Warning: partition %u "
2257 "is empty\n", i + 1);
2258 } else if (first[i] < extended_offset || last[i] > e_last) {
2259 printf("Logical partition %u not entirely in "
2260 "partition %u\n", i + 1, ext_index + 1);
2265 if (total > g_heads * g_sectors * g_cylinders)
2266 printf("Total allocated sectors %u greater than the maximum "
2267 "%u\n", total, g_heads * g_sectors * g_cylinders);
2269 total = g_heads * g_sectors * g_cylinders - total;
2271 printf("%"SECT_FMT"u unallocated sectors\n", total);
2276 add_partition(int n, int sys)
2278 char mesg[256]; /* 48 does not suffice in Japanese */
2279 int i, num_read = 0;
2280 struct partition *p = ptes[n].part_table;
2281 struct partition *q = ptes[ext_index].part_table;
2282 sector_t limit, temp;
2283 sector_t start, stop = 0;
2284 sector_t first[g_partitions], last[g_partitions];
2286 if (p && p->sys_ind) {
2287 printf(msg_part_already_defined, n + 1);
2290 fill_bounds(first, last);
2292 start = sector_offset;
2293 if (display_in_cyl_units || !total_number_of_sectors)
2294 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2296 limit = total_number_of_sectors - 1;
2297 if (extended_offset) {
2298 first[ext_index] = extended_offset;
2299 last[ext_index] = get_start_sect(q) +
2300 get_nr_sects(q) - 1;
2303 start = extended_offset + sector_offset;
2304 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2306 if (display_in_cyl_units)
2307 for (i = 0; i < g_partitions; i++)
2308 first[i] = (cround(first[i]) - 1) * units_per_sector;
2310 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2313 for (i = 0; i < g_partitions; i++) {
2316 if (start == ptes[i].offset)
2317 start += sector_offset;
2318 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2319 if (start >= first[i] && start <= lastplusoff)
2320 start = lastplusoff + 1;
2324 if (start >= temp+units_per_sector && num_read) {
2325 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2329 if (!num_read && start == temp) {
2330 sector_t saved_start;
2332 saved_start = start;
2333 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2335 if (display_in_cyl_units) {
2336 start = (start - 1) * units_per_sector;
2337 if (start < saved_start)
2338 start = saved_start;
2342 } while (start != temp || !num_read);
2343 if (n > 4) { /* NOT for fifth partition */
2344 struct pte *pe = &ptes[n];
2346 pe->offset = start - sector_offset;
2347 if (pe->offset == extended_offset) { /* must be corrected */
2349 if (sector_offset == 1)
2354 for (i = 0; i < g_partitions; i++) {
2355 struct pte *pe = &ptes[i];
2357 if (start < pe->offset && limit >= pe->offset)
2358 limit = pe->offset - 1;
2359 if (start < first[i] && limit >= first[i])
2360 limit = first[i] - 1;
2362 if (start > limit) {
2363 printf("No free sectors available\n");
2368 if (cround(start) == cround(limit)) {
2371 snprintf(mesg, sizeof(mesg),
2372 "Last %s or +size or +sizeM or +sizeK",
2373 str_units(SINGULAR));
2374 stop = read_int(cround(start), cround(limit), cround(limit),
2375 cround(start), mesg);
2376 if (display_in_cyl_units) {
2377 stop = stop * units_per_sector - 1;
2383 set_partition(n, 0, start, stop, sys);
2385 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2387 if (IS_EXTENDED(sys)) {
2388 struct pte *pe4 = &ptes[4];
2389 struct pte *pen = &ptes[n];
2392 pen->ext_pointer = p;
2393 pe4->offset = extended_offset = start;
2394 pe4->sectorbuffer = xzalloc(sector_size);
2395 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2396 pe4->ext_pointer = pe4->part_table + 1;
2405 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2406 struct pte *pe = &ptes[g_partitions];
2408 pe->sectorbuffer = xzalloc(sector_size);
2409 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2410 pe->ext_pointer = pe->part_table + 1;
2415 add_partition(g_partitions - 1, LINUX_NATIVE);
2421 int i, free_primary = 0;
2423 if (warn_geometry())
2427 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2431 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2435 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2436 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2437 "table first (use 'o'). This will destroy the present disk contents.\n");
2441 for (i = 0; i < 4; i++)
2442 free_primary += !ptes[i].part_table->sys_ind;
2444 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2445 printf("The maximum number of partitions has been created\n");
2449 if (!free_primary) {
2450 if (extended_offset)
2453 printf("You must delete some partition and add "
2454 "an extended partition first\n");
2457 snprintf(line, sizeof(line),
2460 " p primary partition (1-4)\n",
2462 "l logical (5 or over)" : "e extended"));
2464 c = read_nonempty(line);
2465 if (c == 'p' || c == 'P') {
2466 i = get_nonexisting_partition(0, 4);
2468 add_partition(i, LINUX_NATIVE);
2471 if (c == 'l' && extended_offset) {
2475 if (c == 'e' && !extended_offset) {
2476 i = get_nonexisting_partition(0, 4);
2478 add_partition(i, EXTENDED);
2481 printf("Invalid partition number "
2482 "for type '%c'\n", c);
2493 for (i = 0; i < 3; i++)
2494 if (ptes[i].changed)
2495 ptes[3].changed = 1;
2496 for (i = 3; i < g_partitions; i++) {
2497 struct pte *pe = &ptes[i];
2500 write_part_table_flag(pe->sectorbuffer);
2501 write_sector(pe->offset, pe->sectorbuffer);
2505 else if (LABEL_IS_SGI) {
2506 /* no test on change? the printf below might be mistaken */
2509 else if (LABEL_IS_SUN) {
2512 for (i = 0; i < 8; i++)
2513 if (ptes[i].changed)
2519 printf("The partition table has been altered!\n\n");
2520 reread_partition_table(1);
2524 reread_partition_table(int leave)
2528 printf("Calling ioctl() to re-read partition table\n");
2530 /* sleep(2); Huh? */
2531 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2532 "WARNING: rereading partition table "
2533 "failed, kernel still uses old table");
2537 "\nWARNING: If you have created or modified any DOS 6.x\n"
2538 "partitions, please see the fdisk manual page for additional\n"
2543 if (ENABLE_FEATURE_CLEAN_UP)
2548 #endif /* FEATURE_FDISK_WRITABLE */
2550 #if ENABLE_FEATURE_FDISK_ADVANCED
2551 #define MAX_PER_LINE 16
2553 print_buffer(char *pbuffer)
2557 for (i = 0, l = 0; i < sector_size; i++, l++) {
2559 printf("0x%03X:", i);
2560 printf(" %02X", (unsigned char) pbuffer[i]);
2561 if (l == MAX_PER_LINE - 1) {
2576 printf("Device: %s\n", disk_device);
2577 if (LABEL_IS_SGI || LABEL_IS_SUN)
2578 print_buffer(MBRbuffer);
2580 for (i = 3; i < g_partitions; i++)
2581 print_buffer(ptes[i].sectorbuffer);
2586 move_begin(unsigned i)
2588 struct pte *pe = &ptes[i];
2589 struct partition *p = pe->part_table;
2590 sector_t new, first;
2592 if (warn_geometry())
2594 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2595 printf("Partition %u has no data area\n", i + 1);
2598 first = get_partition_start(pe);
2599 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2600 "New beginning of data") - pe->offset;
2602 if (new != get_nr_sects(p)) {
2603 first = get_nr_sects(p) + get_start_sect(p) - new;
2604 set_nr_sects(p, first);
2605 set_start_sect(p, new);
2617 c = tolower(read_nonempty("Expert command (m for help): "));
2625 move_begin(get_partition(0, g_partitions));
2628 user_cylinders = g_cylinders =
2629 read_int(1, g_cylinders, 1048576, 0,
2630 "Number of cylinders");
2632 sun_set_ncyl(g_cylinders);
2642 else if (LABEL_IS_SUN)
2644 else if (LABEL_IS_DOS)
2649 fix_partition_table_order();
2652 #if ENABLE_FEATURE_SGI_LABEL
2657 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2676 if (ENABLE_FEATURE_CLEAN_UP)
2683 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2684 "Number of sectors");
2685 if (dos_compatible_flag) {
2686 sector_offset = g_sectors;
2687 printf("Warning: setting sector offset for DOS "
2696 write_table(); /* does not return */
2700 sun_set_pcylcount();
2707 #endif /* ADVANCED mode */
2710 is_ide_cdrom_or_tape(const char *device)
2714 struct stat statbuf;
2717 /* No device was given explicitly, and we are trying some
2718 likely things. But opening /dev/hdc may produce errors like
2719 "hdc: tray open or drive not ready"
2720 if it happens to be a CD-ROM drive. It even happens that
2721 the process hangs on the attempt to read a music CD.
2722 So try to be careful. This only works since 2.1.73. */
2724 if (strncmp("/dev/hd", device, 7))
2727 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2728 procf = fopen_for_read(buf);
2729 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2730 is_ide = (!strncmp(buf, "cdrom", 5) ||
2731 !strncmp(buf, "tape", 4));
2733 /* Now when this proc file does not exist, skip the
2734 device when it is read-only. */
2735 if (stat(device, &statbuf) == 0)
2736 is_ide = ((statbuf.st_mode & 0222) == 0);
2745 open_list_and_close(const char *device, int user_specified)
2749 disk_device = device;
2750 if (setjmp(listingbuf))
2752 if (!user_specified)
2753 if (is_ide_cdrom_or_tape(device))
2756 /* Open disk_device, save file descriptor to dev_fd */
2758 gb = get_boot(TRY_ONLY);
2759 if (gb > 0) { /* I/O error */
2760 /* Ignore other errors, since we try IDE
2761 and SCSI hard disks which may not be
2762 installed on the system. */
2763 if (user_specified || errno == EACCES)
2764 bb_perror_msg("can't open '%s'", device);
2768 if (gb < 0) { /* no DOS signature */
2769 list_disk_geometry();
2772 #if ENABLE_FEATURE_OSF_LABEL
2773 if (bsd_trydev(device) < 0)
2775 printf("Disk %s doesn't contain a valid "
2776 "partition table\n", device);
2779 #if ENABLE_FEATURE_FDISK_WRITABLE
2780 if (!LABEL_IS_SUN && g_partitions > 4) {
2781 delete_partition(ext_index);
2789 /* for fdisk -l: try all things in /proc/partitions
2790 that look like a partition name (do not end in a digit) */
2792 list_devs_in_proc_partititons(void)
2795 char line[100], ptname[100], devname[120], *s;
2798 procpt = fopen_or_warn("/proc/partitions", "r");
2800 while (fgets(line, sizeof(line), procpt)) {
2801 if (sscanf(line, " %u %u %u %[^\n ]",
2802 &ma, &mi, &sz, ptname) != 4)
2804 for (s = ptname; *s; s++)
2806 /* note: excluding '0': e.g. mmcblk0 is not a partition name! */
2807 if (s[-1] >= '1' && s[-1] <= '9')
2809 sprintf(devname, "/dev/%s", ptname);
2810 open_list_and_close(devname, 0);
2812 #if ENABLE_FEATURE_CLEAN_UP
2817 #if ENABLE_FEATURE_FDISK_WRITABLE
2819 unknown_command(int c)
2821 printf("%c: unknown command\n", c);
2825 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2826 int fdisk_main(int argc UNUSED_PARAM, char **argv)
2831 * fdisk -l [-b sectorsize] [-u] device ...
2832 * fdisk -s [partition] ...
2833 * fdisk [-b sectorsize] [-u] device
2835 * Options -C, -H, -S set the geometry.
2839 close_dev_fd(); /* needed: fd 3 must not stay closed */
2841 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2842 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2843 §or_size, &user_cylinders, &user_heads, &user_sectors);
2845 if (opt & OPT_b) { // -b
2846 /* Ugly: this sector size is really per device,
2847 so cannot be combined with multiple disks,
2848 and the same goes for the C/H/S options.
2850 if (sector_size != 512 && sector_size != 1024
2851 && sector_size != 2048)
2854 user_set_sector_size = 1;
2856 if (user_heads <= 0 || user_heads >= 256)
2858 if (user_sectors <= 0 || user_sectors >= 64)
2861 display_in_cyl_units = 0; // -u
2863 #if ENABLE_FEATURE_FDISK_WRITABLE
2870 open_list_and_close(*argv, 1);
2873 /* we don't have device names, */
2874 /* use /proc/partitions instead */
2875 list_devs_in_proc_partititons();
2878 #if ENABLE_FEATURE_FDISK_WRITABLE
2882 #if ENABLE_FEATURE_FDISK_BLKSIZE
2889 for (j = 0; argv[j]; j++) {
2890 unsigned long long size;
2891 fd = xopen(argv[j], O_RDONLY);
2892 size = bb_BLKGETSIZE_sectors(fd) / 2;
2895 printf("%llu\n", size);
2897 printf("%s: %llu\n", argv[j], size);
2903 #if ENABLE_FEATURE_FDISK_WRITABLE
2904 if (!argv[0] || argv[1])
2907 disk_device = argv[0];
2908 get_boot(OPEN_MAIN);
2911 /* OSF label, and no DOS label */
2912 printf("Detected an OSF/1 disklabel on %s, entering "
2913 "disklabel mode\n", disk_device);
2915 /*Why do we do this? It seems to be counter-intuitive*/
2916 current_label_type = LABEL_DOS;
2917 /* If we return we may want to make an empty DOS label? */
2923 c = tolower(read_nonempty("Command (m for help): "));
2927 toggle_active(get_partition(1, g_partitions));
2928 else if (LABEL_IS_SUN)
2929 toggle_sunflags(get_partition(1, g_partitions),
2931 else if (LABEL_IS_SGI)
2932 sgi_set_bootpartition(
2933 get_partition(1, g_partitions));
2939 printf("\nThe current boot file is: %s\n",
2940 sgi_get_bootfile());
2941 if (read_maybe_empty("Please enter the name of the "
2942 "new boot file: ") == '\n')
2943 printf("Boot file unchanged\n");
2945 sgi_set_bootfile(line_ptr);
2947 #if ENABLE_FEATURE_OSF_LABEL
2954 toggle_dos_compatibility_flag();
2955 else if (LABEL_IS_SUN)
2956 toggle_sunflags(get_partition(1, g_partitions),
2958 else if (LABEL_IS_SGI)
2959 sgi_set_swappartition(
2960 get_partition(1, g_partitions));
2967 /* If sgi_label then don't use get_existing_partition,
2968 let the user select a partition, since
2969 get_existing_partition() only works for Linux-like
2971 if (!LABEL_IS_SGI) {
2972 j = get_existing_partition(1, g_partitions);
2974 j = get_partition(1, g_partitions);
2977 delete_partition(j);
2986 list_types(get_sys_types());
3001 if (ENABLE_FEATURE_CLEAN_UP)
3006 #if ENABLE_FEATURE_SUN_LABEL
3020 write_table(); /* does not return */
3022 #if ENABLE_FEATURE_FDISK_ADVANCED
3025 printf("\n\tSorry, no experts menu for SGI "
3026 "partition tables available\n\n");
3037 #endif /* FEATURE_FDISK_WRITABLE */