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 && !isgraph(*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"
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 #define sunlabel ((sun_partition *)MBRbuffer)
656 STATIC_OSF void bsd_select(void);
657 STATIC_OSF void xbsd_print_disklabel(int);
658 #include "fdisk_osf.c"
660 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
662 fdisk_swap16(uint16_t x)
664 return (x << 8) | (x >> 8);
668 fdisk_swap32(uint32_t x)
671 ((x & 0xFF00) << 8) |
672 ((x & 0xFF0000) >> 8) |
677 STATIC_SGI const char *const sgi_sys_types[];
678 STATIC_SGI unsigned sgi_get_num_sectors(int i);
679 STATIC_SGI int sgi_get_sysid(int i);
680 STATIC_SGI void sgi_delete_partition(int i);
681 STATIC_SGI void sgi_change_sysid(int i, int sys);
682 STATIC_SGI void sgi_list_table(int xtra);
683 #if ENABLE_FEATURE_FDISK_ADVANCED
684 STATIC_SGI void sgi_set_xcyl(void);
686 STATIC_SGI int verify_sgi(int verbose);
687 STATIC_SGI void sgi_add_partition(int n, int sys);
688 STATIC_SGI void sgi_set_swappartition(int i);
689 STATIC_SGI const char *sgi_get_bootfile(void);
690 STATIC_SGI void sgi_set_bootfile(const char* aFile);
691 STATIC_SGI void create_sgiinfo(void);
692 STATIC_SGI void sgi_write_table(void);
693 STATIC_SGI void sgi_set_bootpartition(int i);
694 #include "fdisk_sgi.c"
696 STATIC_SUN const char *const sun_sys_types[];
697 STATIC_SUN void sun_delete_partition(int i);
698 STATIC_SUN void sun_change_sysid(int i, int sys);
699 STATIC_SUN void sun_list_table(int xtra);
700 STATIC_SUN void add_sun_partition(int n, int sys);
701 #if ENABLE_FEATURE_FDISK_ADVANCED
702 STATIC_SUN void sun_set_alt_cyl(void);
703 STATIC_SUN void sun_set_ncyl(int cyl);
704 STATIC_SUN void sun_set_xcyl(void);
705 STATIC_SUN void sun_set_ilfact(void);
706 STATIC_SUN void sun_set_rspeed(void);
707 STATIC_SUN void sun_set_pcylcount(void);
709 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
710 STATIC_SUN void verify_sun(void);
711 STATIC_SUN void sun_write_table(void);
712 #include "fdisk_sun.c"
715 #if ENABLE_FEATURE_FDISK_WRITABLE
716 /* start_sect and nr_sects are stored little endian on all machines */
717 /* moreover, they are not aligned correctly */
719 store4_little_endian(unsigned char *cp, unsigned val)
726 #endif /* FEATURE_FDISK_WRITABLE */
729 read4_little_endian(const unsigned char *cp)
731 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
734 #if ENABLE_FEATURE_FDISK_WRITABLE
736 set_start_sect(struct partition *p, unsigned start_sect)
738 store4_little_endian(p->start4, start_sect);
743 get_start_sect(const struct partition *p)
745 return read4_little_endian(p->start4);
748 #if ENABLE_FEATURE_FDISK_WRITABLE
750 set_nr_sects(struct partition *p, unsigned nr_sects)
752 store4_little_endian(p->size4, nr_sects);
757 get_nr_sects(const struct partition *p)
759 return read4_little_endian(p->size4);
762 /* Allocate a buffer and read a partition table sector */
764 read_pte(struct pte *pe, sector_t offset)
767 pe->sectorbuffer = xzalloc(sector_size);
769 /* xread would make us abort - bad for fdisk -l */
770 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
771 fdisk_fatal(unable_to_read);
772 #if ENABLE_FEATURE_FDISK_WRITABLE
775 pe->part_table = pe->ext_pointer = NULL;
779 get_partition_start(const struct pte *pe)
781 return pe->offset + get_start_sect(pe->part_table);
784 #if ENABLE_FEATURE_FDISK_WRITABLE
786 * Avoid warning about DOS partitions when no DOS partition was changed.
787 * Here a heuristic "is probably dos partition".
788 * We might also do the opposite and warn in all cases except
789 * for "is probably nondos partition".
793 is_dos_partition(int t)
795 return (t == 1 || t == 4 || t == 6 ||
796 t == 0x0b || t == 0x0c || t == 0x0e ||
797 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
798 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
799 t == 0xc1 || t == 0xc4 || t == 0xc6);
806 puts("Command Action");
808 puts("a\ttoggle a read only flag"); /* sun */
809 puts("b\tedit bsd disklabel");
810 puts("c\ttoggle the mountable flag"); /* sun */
811 puts("d\tdelete a partition");
812 puts("l\tlist known partition types");
813 puts("n\tadd a new partition");
814 puts("o\tcreate a new empty DOS partition table");
815 puts("p\tprint the partition table");
816 puts("q\tquit without saving changes");
817 puts("s\tcreate a new empty Sun disklabel"); /* sun */
818 puts("t\tchange a partition's system id");
819 puts("u\tchange display/entry units");
820 puts("v\tverify the partition table");
821 puts("w\twrite table to disk and exit");
822 #if ENABLE_FEATURE_FDISK_ADVANCED
823 puts("x\textra functionality (experts only)");
825 } else if (LABEL_IS_SGI) {
826 puts("a\tselect bootable partition"); /* sgi flavour */
827 puts("b\tedit bootfile entry"); /* sgi */
828 puts("c\tselect sgi swap partition"); /* sgi flavour */
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 } else if (LABEL_IS_AIX) {
841 puts("o\tcreate a new empty DOS partition table");
842 puts("q\tquit without saving changes");
843 puts("s\tcreate a new empty Sun disklabel"); /* sun */
845 puts("a\ttoggle a bootable flag");
846 puts("b\tedit bsd disklabel");
847 puts("c\ttoggle the dos compatibility flag");
848 puts("d\tdelete a partition");
849 puts("l\tlist known partition types");
850 puts("n\tadd a new partition");
851 puts("o\tcreate a new empty DOS partition table");
852 puts("p\tprint the partition table");
853 puts("q\tquit without saving changes");
854 puts("s\tcreate a new empty Sun disklabel"); /* sun */
855 puts("t\tchange a partition's system id");
856 puts("u\tchange display/entry units");
857 puts("v\tverify the partition table");
858 puts("w\twrite table to disk and exit");
859 #if ENABLE_FEATURE_FDISK_ADVANCED
860 puts("x\textra functionality (experts only)");
864 #endif /* FEATURE_FDISK_WRITABLE */
867 #if ENABLE_FEATURE_FDISK_ADVANCED
871 puts("Command Action");
873 puts("a\tchange number of alternate cylinders"); /*sun*/
874 puts("c\tchange number of cylinders");
875 puts("d\tprint the raw data in the partition table");
876 puts("e\tchange number of extra sectors per cylinder");/*sun*/
877 puts("h\tchange number of heads");
878 puts("i\tchange interleave factor"); /*sun*/
879 puts("o\tchange rotation speed (rpm)"); /*sun*/
880 puts("p\tprint the partition table");
881 puts("q\tquit without saving changes");
882 puts("r\treturn to main menu");
883 puts("s\tchange number of sectors/track");
884 puts("v\tverify the partition table");
885 puts("w\twrite table to disk and exit");
886 puts("y\tchange number of physical cylinders"); /*sun*/
887 } else if (LABEL_IS_SGI) {
888 puts("b\tmove beginning of data in a partition"); /* !sun */
889 puts("c\tchange number of cylinders");
890 puts("d\tprint the raw data in the partition table");
891 puts("e\tlist extended partitions"); /* !sun */
892 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
893 puts("h\tchange number of heads");
894 puts("p\tprint the partition table");
895 puts("q\tquit without saving changes");
896 puts("r\treturn to main menu");
897 puts("s\tchange number of sectors/track");
898 puts("v\tverify the partition table");
899 puts("w\twrite table to disk and exit");
900 } else if (LABEL_IS_AIX) {
901 puts("b\tmove beginning of data in a partition"); /* !sun */
902 puts("c\tchange number of cylinders");
903 puts("d\tprint the raw data in the partition table");
904 puts("e\tlist extended partitions"); /* !sun */
905 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
906 puts("h\tchange number of heads");
907 puts("p\tprint the partition table");
908 puts("q\tquit without saving changes");
909 puts("r\treturn to main menu");
910 puts("s\tchange number of sectors/track");
911 puts("v\tverify the partition table");
912 puts("w\twrite table to disk and exit");
914 puts("b\tmove beginning of data in a partition"); /* !sun */
915 puts("c\tchange number of cylinders");
916 puts("d\tprint the raw data in the partition table");
917 puts("e\tlist extended partitions"); /* !sun */
918 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
919 #if ENABLE_FEATURE_SGI_LABEL
920 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
922 puts("h\tchange number of heads");
923 puts("p\tprint the partition table");
924 puts("q\tquit without saving changes");
925 puts("r\treturn to main menu");
926 puts("s\tchange number of sectors/track");
927 puts("v\tverify the partition table");
928 puts("w\twrite table to disk and exit");
931 #endif /* ADVANCED mode */
933 #if ENABLE_FEATURE_FDISK_WRITABLE
934 static const char *const *
938 LABEL_IS_SUN ? sun_sys_types :
939 LABEL_IS_SGI ? sgi_sys_types :
943 #define get_sys_types() i386_sys_types
944 #endif /* FEATURE_FDISK_WRITABLE */
947 partition_type(unsigned char type)
950 const char *const *types = get_sys_types();
952 for (i = 0; types[i]; i++)
953 if ((unsigned char)types[i][0] == type)
960 #if ENABLE_FEATURE_FDISK_WRITABLE
964 return LABEL_IS_SUN ? sunlabel->infos[i].id :
965 (LABEL_IS_SGI ? sgi_get_sysid(i) :
966 ptes[i].part_table->sys_ind);
970 list_types(const char *const *sys)
975 unsigned done, next, size;
978 for (size = 0; sys[size]; size++)
982 for (i = COLS-1; i >= 0; i--) {
983 done += (size + i - done) / (i + 1);
984 last[COLS-1 - i] = done;
989 printf("%c%2x %-22.22s", i ? ' ' : '\n',
990 (unsigned char)sys[next][0],
992 next = last[i++] + done;
993 if (i >= COLS || next >= last[i]) {
997 } while (done < last[0]);
1000 #endif /* FEATURE_FDISK_WRITABLE */
1003 is_cleared_partition(const struct partition *p)
1005 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
1006 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
1007 get_start_sect(p) || get_nr_sects(p));
1011 clear_partition(struct partition *p)
1015 memset(p, 0, sizeof(struct partition));
1018 #if ENABLE_FEATURE_FDISK_WRITABLE
1020 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1022 struct partition *p;
1026 p = ptes[i].ext_pointer;
1027 offset = extended_offset;
1029 p = ptes[i].part_table;
1030 offset = ptes[i].offset;
1034 set_start_sect(p, start - offset);
1035 set_nr_sects(p, stop - start + 1);
1036 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1037 start = g_heads * g_sectors * 1024 - 1;
1038 set_hsc(p->head, p->sector, p->cyl, start);
1039 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1040 stop = g_heads * g_sectors * 1024 - 1;
1041 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1042 ptes[i].changed = 1;
1049 if (g_heads && g_sectors && g_cylinders)
1052 printf("Unknown value(s) for:");
1058 printf(" cylinders");
1060 #if ENABLE_FEATURE_FDISK_WRITABLE
1061 " (settable in the extra functions menu)"
1070 int cyl_units = g_heads * g_sectors;
1072 if (display_in_cyl_units && cyl_units)
1073 units_per_sector = cyl_units;
1075 units_per_sector = 1; /* in sectors */
1078 #if ENABLE_FEATURE_FDISK_WRITABLE
1080 warn_cylinders(void)
1082 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1084 "The number of cylinders for this disk is set to %u.\n"
1085 "There is nothing wrong with that, but this is larger than 1024,\n"
1086 "and could in certain setups cause problems with:\n"
1087 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1088 "2) booting and partitioning software from other OSs\n"
1089 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1095 read_extended(int ext)
1099 struct partition *p, *q;
1103 pex->ext_pointer = pex->part_table;
1105 p = pex->part_table;
1106 if (!get_start_sect(p)) {
1107 printf("Bad offset in primary extended partition\n");
1111 while (IS_EXTENDED(p->sys_ind)) {
1112 struct pte *pe = &ptes[g_partitions];
1114 if (g_partitions >= MAXIMUM_PARTS) {
1115 /* This is not a Linux restriction, but
1116 this program uses arrays of size MAXIMUM_PARTS.
1117 Do not try to 'improve' this test. */
1118 struct pte *pre = &ptes[g_partitions - 1];
1119 #if ENABLE_FEATURE_FDISK_WRITABLE
1120 printf("Warning: deleting partitions after %u\n",
1124 clear_partition(pre->ext_pointer);
1128 read_pte(pe, extended_offset + get_start_sect(p));
1130 if (!extended_offset)
1131 extended_offset = get_start_sect(p);
1133 q = p = pt_offset(pe->sectorbuffer, 0);
1134 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1135 if (IS_EXTENDED(p->sys_ind)) {
1136 if (pe->ext_pointer)
1137 printf("Warning: extra link "
1138 "pointer in partition table"
1139 " %u\n", g_partitions + 1);
1141 pe->ext_pointer = p;
1142 } else if (p->sys_ind) {
1144 printf("Warning: ignoring extra "
1145 "data in partition table"
1146 " %u\n", g_partitions + 1);
1152 /* very strange code here... */
1153 if (!pe->part_table) {
1154 if (q != pe->ext_pointer)
1157 pe->part_table = q + 1;
1159 if (!pe->ext_pointer) {
1160 if (q != pe->part_table)
1161 pe->ext_pointer = q;
1163 pe->ext_pointer = q + 1;
1166 p = pe->ext_pointer;
1170 #if ENABLE_FEATURE_FDISK_WRITABLE
1171 /* remove empty links */
1173 for (i = 4; i < g_partitions; i++) {
1174 struct pte *pe = &ptes[i];
1176 if (!get_nr_sects(pe->part_table)
1177 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1179 printf("Omitting empty partition (%u)\n", i+1);
1180 delete_partition(i);
1181 goto remove; /* numbering changed */
1187 #if ENABLE_FEATURE_FDISK_WRITABLE
1189 create_doslabel(void)
1193 printf(msg_building_new_label, "DOS disklabel");
1195 current_label_type = LABEL_DOS;
1197 #if ENABLE_FEATURE_OSF_LABEL
1198 possibly_osf_label = 0;
1202 for (i = 510-64; i < 510; i++)
1204 write_part_table_flag(MBRbuffer);
1205 extended_offset = 0;
1206 set_all_unchanged();
1208 get_boot(CREATE_EMPTY_DOS);
1210 #endif /* FEATURE_FDISK_WRITABLE */
1213 get_sectorsize(void)
1215 if (!user_set_sector_size) {
1217 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1219 if (sector_size != DEFAULT_SECTOR_SIZE)
1220 printf("Note: sector size is %u "
1221 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1227 get_kernel_geometry(void)
1229 struct hd_geometry geometry;
1231 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1232 kern_heads = geometry.heads;
1233 kern_sectors = geometry.sectors;
1234 /* never use geometry.cylinders - it is truncated */
1239 get_partition_table_geometry(void)
1241 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1242 struct partition *p;
1243 int i, h, s, hh, ss;
1247 if (!(valid_part_table_flag((char*)bufp)))
1251 for (i = 0; i < 4; i++) {
1252 p = pt_offset(bufp, i);
1253 if (p->sys_ind != 0) {
1254 h = p->end_head + 1;
1255 s = (p->end_sector & 077);
1260 } else if (hh != h || ss != s)
1265 if (!first && !bad) {
1277 sec_fac = sector_size / 512;
1278 #if ENABLE_FEATURE_SUN_LABEL
1279 guess_device_type();
1281 g_heads = g_cylinders = g_sectors = 0;
1282 kern_heads = kern_sectors = 0;
1283 pt_heads = pt_sectors = 0;
1285 get_kernel_geometry();
1286 get_partition_table_geometry();
1288 g_heads = user_heads ? user_heads :
1289 pt_heads ? pt_heads :
1290 kern_heads ? kern_heads : 255;
1291 g_sectors = user_sectors ? user_sectors :
1292 pt_sectors ? pt_sectors :
1293 kern_sectors ? kern_sectors : 63;
1294 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1297 if (dos_compatible_flag)
1298 sector_offset = g_sectors;
1300 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1302 g_cylinders = user_cylinders;
1306 * Opens disk_device and optionally reads MBR.
1307 * FIXME: document what each 'what' value will do!
1309 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1310 * 0: found or created label
1313 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1314 static int get_boot(enum action what)
1316 static int get_boot(void)
1317 #define get_boot(what) get_boot()
1323 for (i = 0; i < 4; i++) {
1324 struct pte *pe = &ptes[i];
1325 pe->part_table = pt_offset(MBRbuffer, i);
1326 pe->ext_pointer = NULL;
1328 pe->sectorbuffer = MBRbuffer;
1329 #if ENABLE_FEATURE_FDISK_WRITABLE
1330 pe->changed = (what == CREATE_EMPTY_DOS);
1334 #if ENABLE_FEATURE_FDISK_WRITABLE
1335 // ALERT! highly idiotic design!
1336 // We end up here when we call get_boot() recursively
1337 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1338 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1339 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1340 // So skip opening device _again_...
1341 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1344 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1347 fd = open(disk_device, O_RDONLY);
1349 if (what == TRY_ONLY)
1351 fdisk_fatal(unable_to_open);
1353 printf("'%s' is opened for read only\n", disk_device);
1355 xmove_fd(fd, dev_fd);
1356 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1357 if (what == TRY_ONLY) {
1361 fdisk_fatal(unable_to_read);
1364 fd = open(disk_device, O_RDONLY);
1367 if (512 != full_read(fd, MBRbuffer, 512)) {
1371 xmove_fd(fd, dev_fd);
1377 #if ENABLE_FEATURE_SUN_LABEL
1378 if (check_sun_label())
1381 #if ENABLE_FEATURE_SGI_LABEL
1382 if (check_sgi_label())
1385 #if ENABLE_FEATURE_AIX_LABEL
1386 if (check_aix_label())
1389 #if ENABLE_FEATURE_OSF_LABEL
1390 if (check_osf_label()) {
1391 possibly_osf_label = 1;
1392 if (!valid_part_table_flag(MBRbuffer)) {
1393 current_label_type = LABEL_OSF;
1396 printf("This disk has both DOS and BSD magic.\n"
1397 "Give the 'b' command to go to BSD mode.\n");
1401 #if !ENABLE_FEATURE_FDISK_WRITABLE
1402 if (!valid_part_table_flag(MBRbuffer))
1405 if (!valid_part_table_flag(MBRbuffer)) {
1406 if (what == OPEN_MAIN) {
1407 printf("Device contains neither a valid DOS "
1408 "partition table, nor Sun, SGI or OSF "
1411 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1421 #endif /* FEATURE_FDISK_WRITABLE */
1424 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1427 for (i = 0; i < 4; i++) {
1428 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1429 if (g_partitions != 4)
1430 printf("Ignoring extra extended "
1431 "partition %u\n", i + 1);
1437 for (i = 3; i < g_partitions; i++) {
1438 struct pte *pe = &ptes[i];
1439 if (!valid_part_table_flag(pe->sectorbuffer)) {
1440 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1441 "table %u will be corrected by w(rite)\n",
1442 pe->sectorbuffer[510],
1443 pe->sectorbuffer[511],
1445 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1452 #if ENABLE_FEATURE_FDISK_WRITABLE
1454 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1455 * If the user hits Enter, DFLT is returned.
1456 * Answers like +10 are interpreted as offsets from BASE.
1458 * There is no default if DFLT is not between LOW and HIGH.
1461 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1465 const char *fmt = "%s (%u-%u, default %u): ";
1467 if (dflt < low || dflt > high) {
1468 fmt = "%s (%u-%u): ";
1473 int use_default = default_ok;
1475 /* ask question and read answer */
1477 printf(fmt, mesg, low, high, dflt);
1478 read_maybe_empty("");
1479 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1480 && *line_ptr != '-' && *line_ptr != '+');
1482 if (*line_ptr == '+' || *line_ptr == '-') {
1483 int minus = (*line_ptr == '-');
1486 value = atoi(line_ptr + 1);
1488 /* (1) if 2nd char is digit, use_default = 0.
1489 * (2) move line_ptr to first non-digit. */
1490 while (isdigit(*++line_ptr))
1493 switch (*line_ptr) {
1496 if (!display_in_cyl_units)
1497 value *= g_heads * g_sectors;
1511 absolute = 1000000000;
1520 bytes = (ullong) value * absolute;
1521 unit = sector_size * units_per_sector;
1522 bytes += unit/2; /* round */
1530 value = atoi(line_ptr);
1531 while (isdigit(*line_ptr)) {
1538 printf("Using default value %u\n", value);
1540 if (value >= low && value <= high)
1542 printf("Value is out of range\n");
1548 get_partition(int warn, unsigned max)
1553 i = read_int(1, 0, max, 0, "Partition number") - 1;
1557 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1558 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1559 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1561 printf("Warning: partition %u has empty type\n", i+1);
1568 get_existing_partition(int warn, unsigned max)
1573 for (i = 0; i < max; i++) {
1574 struct pte *pe = &ptes[i];
1575 struct partition *p = pe->part_table;
1577 if (p && !is_cleared_partition(p)) {
1584 printf("Selected partition %u\n", pno+1);
1587 printf("No partition is defined yet!\n");
1591 return get_partition(warn, max);
1595 get_nonexisting_partition(int warn, unsigned max)
1600 for (i = 0; i < max; i++) {
1601 struct pte *pe = &ptes[i];
1602 struct partition *p = pe->part_table;
1604 if (p && is_cleared_partition(p)) {
1611 printf("Selected partition %u\n", pno+1);
1614 printf("All primary partitions have been defined already!\n");
1618 return get_partition(warn, max);
1625 display_in_cyl_units = !display_in_cyl_units;
1627 printf("Changing display/entry units to %s\n",
1632 toggle_active(int i)
1634 struct pte *pe = &ptes[i];
1635 struct partition *p = pe->part_table;
1637 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1638 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1639 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1644 toggle_dos_compatibility_flag(void)
1646 dos_compatible_flag = 1 - dos_compatible_flag;
1647 if (dos_compatible_flag) {
1648 sector_offset = g_sectors;
1649 printf("DOS Compatibility flag is set\n");
1652 printf("DOS Compatibility flag is not set\n");
1657 delete_partition(int i)
1659 struct pte *pe = &ptes[i];
1660 struct partition *p = pe->part_table;
1661 struct partition *q = pe->ext_pointer;
1663 /* Note that for the fifth partition (i == 4) we don't actually
1664 * decrement partitions.
1667 if (warn_geometry())
1668 return; /* C/H/S not set */
1672 sun_delete_partition(i);
1676 sgi_delete_partition(i);
1681 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1683 ptes[ext_index].ext_pointer = NULL;
1684 extended_offset = 0;
1690 if (!q->sys_ind && i > 4) {
1691 /* the last one in the chain - just delete */
1694 clear_partition(ptes[i].ext_pointer);
1695 ptes[i].changed = 1;
1697 /* not the last one - further ones will be moved down */
1699 /* delete this link in the chain */
1700 p = ptes[i-1].ext_pointer;
1702 set_start_sect(p, get_start_sect(q));
1703 set_nr_sects(p, get_nr_sects(q));
1704 ptes[i-1].changed = 1;
1705 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1706 /* the first logical in a longer chain */
1709 if (pe->part_table) /* prevent SEGFAULT */
1710 set_start_sect(pe->part_table,
1711 get_partition_start(pe) -
1713 pe->offset = extended_offset;
1717 if (g_partitions > 5) {
1719 while (i < g_partitions) {
1720 ptes[i] = ptes[i+1];
1724 /* the only logical: clear only */
1725 clear_partition(ptes[i].part_table);
1732 int i, sys, origsys;
1733 struct partition *p;
1735 /* If sgi_label then don't use get_existing_partition,
1736 let the user select a partition, since get_existing_partition()
1737 only works for Linux like partition tables. */
1738 if (!LABEL_IS_SGI) {
1739 i = get_existing_partition(0, g_partitions);
1741 i = get_partition(0, g_partitions);
1745 p = ptes[i].part_table;
1746 origsys = sys = get_sysid(i);
1748 /* if changing types T to 0 is allowed, then
1749 the reverse change must be allowed, too */
1750 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1751 printf("Partition %u does not exist yet!\n", i + 1);
1755 sys = read_hex(get_sys_types());
1757 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1758 printf("Type 0 means free space to many systems\n"
1759 "(but not to Linux). Having partitions of\n"
1760 "type 0 is probably unwise.\n");
1764 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1765 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1766 printf("You cannot change a partition into"
1767 " an extended one or vice versa\n");
1773 #if ENABLE_FEATURE_SUN_LABEL
1774 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1775 printf("Consider leaving partition 3 "
1776 "as Whole disk (5),\n"
1777 "as SunOS/Solaris expects it and "
1778 "even Linux likes it\n\n");
1780 #if ENABLE_FEATURE_SGI_LABEL
1783 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1784 (i == 8 && sys != 0)
1787 printf("Consider leaving partition 9 "
1788 "as volume header (0),\nand "
1789 "partition 11 as entire volume (6)"
1790 "as IRIX expects it\n\n");
1796 sun_change_sysid(i, sys);
1797 } else if (LABEL_IS_SGI) {
1798 sgi_change_sysid(i, sys);
1802 printf("Changed system type of partition %u "
1803 "to %x (%s)\n", i + 1, sys,
1804 partition_type(sys));
1805 ptes[i].changed = 1;
1806 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1812 #endif /* FEATURE_FDISK_WRITABLE */
1815 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1816 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1817 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1818 * Lubkin Oct. 1991). */
1821 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1823 int spc = g_heads * g_sectors;
1827 *h = ls / g_sectors;
1828 *s = ls % g_sectors + 1; /* sectors count from 1 */
1832 check_consistency(const struct partition *p, int partition)
1834 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1835 unsigned pec, peh, pes; /* physical ending c, h, s */
1836 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1837 unsigned lec, leh, les; /* logical ending c, h, s */
1839 if (!g_heads || !g_sectors || (partition >= 4))
1840 return; /* do not check extended partitions */
1842 /* physical beginning c, h, s */
1843 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1845 pbs = p->sector & 0x3f;
1847 /* physical ending c, h, s */
1848 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1850 pes = p->end_sector & 0x3f;
1852 /* compute logical beginning (c, h, s) */
1853 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1855 /* compute logical ending (c, h, s) */
1856 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1858 /* Same physical / logical beginning? */
1859 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1860 printf("Partition %u has different physical/logical "
1861 "beginnings (non-Linux?):\n", partition + 1);
1862 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
1863 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
1866 /* Same physical / logical ending? */
1867 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1868 printf("Partition %u has different physical/logical "
1869 "endings:\n", partition + 1);
1870 printf(" phys=(%u, %u, %u) ", pec, peh, pes);
1871 printf("logical=(%u, %u, %u)\n", lec, leh, les);
1874 /* Ending on cylinder boundary? */
1875 if (peh != (g_heads - 1) || pes != g_sectors) {
1876 printf("Partition %u does not end on cylinder boundary\n",
1882 list_disk_geometry(void)
1884 ullong bytes = ((ullong)total_number_of_sectors << 9);
1885 long megabytes = bytes / 1000000;
1887 if (megabytes < 10000)
1888 printf("\nDisk %s: %lu MB, %llu bytes\n",
1889 disk_device, megabytes, bytes);
1891 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1892 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1893 printf("%u heads, %u sectors/track, %u cylinders",
1894 g_heads, g_sectors, g_cylinders);
1895 if (units_per_sector == 1)
1896 printf(", total %"SECT_FMT"u sectors",
1897 total_number_of_sectors / (sector_size/512));
1898 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1900 units_per_sector, sector_size, units_per_sector * sector_size);
1904 * Check whether partition entries are ordered by their starting positions.
1905 * Return 0 if OK. Return i if partition i should have been earlier.
1906 * Two separate checks: primary and logical partitions.
1909 wrong_p_order(int *prev)
1911 const struct pte *pe;
1912 const struct partition *p;
1913 sector_t last_p_start_pos = 0, p_start_pos;
1914 unsigned i, last_i = 0;
1916 for (i = 0; i < g_partitions; i++) {
1919 last_p_start_pos = 0;
1924 p_start_pos = get_partition_start(pe);
1926 if (last_p_start_pos > p_start_pos) {
1932 last_p_start_pos = p_start_pos;
1939 #if ENABLE_FEATURE_FDISK_ADVANCED
1941 * Fix the chain of logicals.
1942 * extended_offset is unchanged, the set of sectors used is unchanged
1943 * The chain is sorted so that sectors increase, and so that
1944 * starting sectors increase.
1946 * After this it may still be that cfdisk doesnt like the table.
1947 * (This is because cfdisk considers expanded parts, from link to
1948 * end of partition, and these may still overlap.)
1950 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1954 fix_chain_of_logicals(void)
1956 int j, oj, ojj, sj, sjj;
1957 struct partition *pj,*pjj,tmp;
1959 /* Stage 1: sort sectors but leave sector of part 4 */
1960 /* (Its sector is the global extended_offset.) */
1962 for (j = 5; j < g_partitions - 1; j++) {
1963 oj = ptes[j].offset;
1964 ojj = ptes[j+1].offset;
1966 ptes[j].offset = ojj;
1967 ptes[j+1].offset = oj;
1968 pj = ptes[j].part_table;
1969 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1970 pjj = ptes[j+1].part_table;
1971 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1972 set_start_sect(ptes[j-1].ext_pointer,
1973 ojj-extended_offset);
1974 set_start_sect(ptes[j].ext_pointer,
1975 oj-extended_offset);
1980 /* Stage 2: sort starting sectors */
1982 for (j = 4; j < g_partitions - 1; j++) {
1983 pj = ptes[j].part_table;
1984 pjj = ptes[j+1].part_table;
1985 sj = get_start_sect(pj);
1986 sjj = get_start_sect(pjj);
1987 oj = ptes[j].offset;
1988 ojj = ptes[j+1].offset;
1989 if (oj+sj > ojj+sjj) {
1993 set_start_sect(pj, ojj+sjj-oj);
1994 set_start_sect(pjj, oj+sj-ojj);
1999 /* Probably something was changed */
2000 for (j = 4; j < g_partitions; j++)
2001 ptes[j].changed = 1;
2006 fix_partition_table_order(void)
2008 struct pte *pei, *pek;
2011 if (!wrong_p_order(NULL)) {
2012 printf("Ordering is already correct\n\n");
2016 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2017 /* partition i should have come earlier, move it */
2018 /* We have to move data in the MBR */
2019 struct partition *pi, *pk, *pe, pbuf;
2023 pe = pei->ext_pointer;
2024 pei->ext_pointer = pek->ext_pointer;
2025 pek->ext_pointer = pe;
2027 pi = pei->part_table;
2028 pk = pek->part_table;
2030 memmove(&pbuf, pi, sizeof(struct partition));
2031 memmove(pi, pk, sizeof(struct partition));
2032 memmove(pk, &pbuf, sizeof(struct partition));
2034 pei->changed = pek->changed = 1;
2038 fix_chain_of_logicals();
2046 list_table(int xtra)
2048 const struct partition *p;
2052 sun_list_table(xtra);
2056 sgi_list_table(xtra);
2060 list_disk_geometry();
2063 xbsd_print_disklabel(xtra);
2067 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2068 but if the device name ends in a digit, say /dev/foo1,
2069 then the partition is called /dev/foo1p3. */
2070 w = strlen(disk_device);
2071 if (w && isdigit(disk_device[w-1]))
2076 // 1 12345678901 12345678901 12345678901 12
2077 printf("%*s Boot Start End Blocks Id System\n",
2080 for (i = 0; i < g_partitions; i++) {
2081 const struct pte *pe = &ptes[i];
2087 if (!p || is_cleared_partition(p))
2090 psects = get_nr_sects(p);
2094 if (sector_size < 1024) {
2095 pblocks /= (1024 / sector_size);
2096 podd = psects % (1024 / sector_size);
2098 if (sector_size > 1024)
2099 pblocks *= (sector_size / 1024);
2101 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
2102 partname(disk_device, i+1, w+2),
2103 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2105 cround(get_partition_start(pe)), /* start */
2106 cround(get_partition_start(pe) + psects /* end */
2107 - (psects ? 1 : 0)),
2108 pblocks, podd ? '+' : ' ', /* odd flag on end */
2109 p->sys_ind, /* type id */
2110 partition_type(p->sys_ind)); /* type name */
2112 check_consistency(p, i);
2115 /* Is partition table in disk order? It need not be, but... */
2116 /* partition table entries are not checked for correct order
2117 * if this is a sgi, sun or aix labeled disk... */
2118 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2120 printf("\nPartition table entries are not in disk order\n");
2124 #if ENABLE_FEATURE_FDISK_ADVANCED
2126 x_list_table(int extend)
2128 const struct pte *pe;
2129 const struct partition *p;
2132 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2133 disk_device, g_heads, g_sectors, g_cylinders);
2134 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2135 for (i = 0; i < g_partitions; i++) {
2137 p = (extend ? pe->ext_pointer : pe->part_table);
2139 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2140 i + 1, p->boot_ind, p->head,
2142 cylinder(p->sector, p->cyl), p->end_head,
2143 sector(p->end_sector),
2144 cylinder(p->end_sector, p->end_cyl),
2145 get_start_sect(p), get_nr_sects(p),
2148 check_consistency(p, i);
2154 #if ENABLE_FEATURE_FDISK_WRITABLE
2156 fill_bounds(sector_t *first, sector_t *last)
2159 const struct pte *pe = &ptes[0];
2160 const struct partition *p;
2162 for (i = 0; i < g_partitions; pe++,i++) {
2164 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2165 first[i] = 0xffffffff;
2168 first[i] = get_partition_start(pe);
2169 last[i] = first[i] + get_nr_sects(p) - 1;
2175 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2177 sector_t total, real_s, real_c;
2179 real_s = sector(s) - 1;
2180 real_c = cylinder(s, c);
2181 total = (real_c * g_sectors + real_s) * g_heads + h;
2183 printf("Partition %u contains sector 0\n", n);
2185 printf("Partition %u: head %u greater than maximum %u\n",
2187 if (real_s >= g_sectors)
2188 printf("Partition %u: sector %u greater than "
2189 "maximum %u\n", n, s, g_sectors);
2190 if (real_c >= g_cylinders)
2191 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2192 "maximum %u\n", n, real_c + 1, g_cylinders);
2193 if (g_cylinders <= 1024 && start != total)
2194 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2195 "total %"SECT_FMT"u\n", n, start, total);
2203 sector_t first[g_partitions], last[g_partitions];
2204 struct partition *p;
2206 if (warn_geometry())
2218 fill_bounds(first, last);
2219 for (i = 0; i < g_partitions; i++) {
2220 struct pte *pe = &ptes[i];
2223 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2224 check_consistency(p, i);
2225 if (get_partition_start(pe) < first[i])
2226 printf("Warning: bad start-of-data in "
2227 "partition %u\n", i + 1);
2228 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2230 total += last[i] + 1 - first[i];
2231 for (j = 0; j < i; j++) {
2232 if ((first[i] >= first[j] && first[i] <= last[j])
2233 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2234 printf("Warning: partition %u overlaps "
2235 "partition %u\n", j + 1, i + 1);
2236 total += first[i] >= first[j] ?
2237 first[i] : first[j];
2238 total -= last[i] <= last[j] ?
2245 if (extended_offset) {
2246 struct pte *pex = &ptes[ext_index];
2247 sector_t e_last = get_start_sect(pex->part_table) +
2248 get_nr_sects(pex->part_table) - 1;
2250 for (i = 4; i < g_partitions; i++) {
2252 p = ptes[i].part_table;
2254 if (i != 4 || i + 1 < g_partitions)
2255 printf("Warning: partition %u "
2256 "is empty\n", i + 1);
2257 } else if (first[i] < extended_offset || last[i] > e_last) {
2258 printf("Logical partition %u not entirely in "
2259 "partition %u\n", i + 1, ext_index + 1);
2264 if (total > g_heads * g_sectors * g_cylinders)
2265 printf("Total allocated sectors %u greater than the maximum "
2266 "%u\n", total, g_heads * g_sectors * g_cylinders);
2268 total = g_heads * g_sectors * g_cylinders - total;
2270 printf("%"SECT_FMT"u unallocated sectors\n", total);
2275 add_partition(int n, int sys)
2277 char mesg[256]; /* 48 does not suffice in Japanese */
2278 int i, num_read = 0;
2279 struct partition *p = ptes[n].part_table;
2280 struct partition *q = ptes[ext_index].part_table;
2281 sector_t limit, temp;
2282 sector_t start, stop = 0;
2283 sector_t first[g_partitions], last[g_partitions];
2285 if (p && p->sys_ind) {
2286 printf(msg_part_already_defined, n + 1);
2289 fill_bounds(first, last);
2291 start = sector_offset;
2292 if (display_in_cyl_units || !total_number_of_sectors)
2293 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2295 limit = total_number_of_sectors - 1;
2296 if (extended_offset) {
2297 first[ext_index] = extended_offset;
2298 last[ext_index] = get_start_sect(q) +
2299 get_nr_sects(q) - 1;
2302 start = extended_offset + sector_offset;
2303 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2305 if (display_in_cyl_units)
2306 for (i = 0; i < g_partitions; i++)
2307 first[i] = (cround(first[i]) - 1) * units_per_sector;
2309 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2312 for (i = 0; i < g_partitions; i++) {
2315 if (start == ptes[i].offset)
2316 start += sector_offset;
2317 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2318 if (start >= first[i] && start <= lastplusoff)
2319 start = lastplusoff + 1;
2323 if (start >= temp+units_per_sector && num_read) {
2324 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2328 if (!num_read && start == temp) {
2329 sector_t saved_start;
2331 saved_start = start;
2332 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2334 if (display_in_cyl_units) {
2335 start = (start - 1) * units_per_sector;
2336 if (start < saved_start)
2337 start = saved_start;
2341 } while (start != temp || !num_read);
2342 if (n > 4) { /* NOT for fifth partition */
2343 struct pte *pe = &ptes[n];
2345 pe->offset = start - sector_offset;
2346 if (pe->offset == extended_offset) { /* must be corrected */
2348 if (sector_offset == 1)
2353 for (i = 0; i < g_partitions; i++) {
2354 struct pte *pe = &ptes[i];
2356 if (start < pe->offset && limit >= pe->offset)
2357 limit = pe->offset - 1;
2358 if (start < first[i] && limit >= first[i])
2359 limit = first[i] - 1;
2361 if (start > limit) {
2362 printf("No free sectors available\n");
2367 if (cround(start) == cround(limit)) {
2370 snprintf(mesg, sizeof(mesg),
2371 "Last %s or +size or +sizeM or +sizeK",
2372 str_units(SINGULAR));
2373 stop = read_int(cround(start), cround(limit), cround(limit),
2374 cround(start), mesg);
2375 if (display_in_cyl_units) {
2376 stop = stop * units_per_sector - 1;
2382 set_partition(n, 0, start, stop, sys);
2384 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2386 if (IS_EXTENDED(sys)) {
2387 struct pte *pe4 = &ptes[4];
2388 struct pte *pen = &ptes[n];
2391 pen->ext_pointer = p;
2392 pe4->offset = extended_offset = start;
2393 pe4->sectorbuffer = xzalloc(sector_size);
2394 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2395 pe4->ext_pointer = pe4->part_table + 1;
2404 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2405 struct pte *pe = &ptes[g_partitions];
2407 pe->sectorbuffer = xzalloc(sector_size);
2408 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2409 pe->ext_pointer = pe->part_table + 1;
2414 add_partition(g_partitions - 1, LINUX_NATIVE);
2420 int i, free_primary = 0;
2422 if (warn_geometry())
2426 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2430 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2434 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2435 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2436 "table first (use 'o'). This will destroy the present disk contents.\n");
2440 for (i = 0; i < 4; i++)
2441 free_primary += !ptes[i].part_table->sys_ind;
2443 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2444 printf("The maximum number of partitions has been created\n");
2448 if (!free_primary) {
2449 if (extended_offset)
2452 printf("You must delete some partition and add "
2453 "an extended partition first\n");
2456 snprintf(line, sizeof(line),
2459 " p primary partition (1-4)\n",
2461 "l logical (5 or over)" : "e extended"));
2463 c = read_nonempty(line);
2464 if (c == 'p' || c == 'P') {
2465 i = get_nonexisting_partition(0, 4);
2467 add_partition(i, LINUX_NATIVE);
2470 if (c == 'l' && extended_offset) {
2474 if (c == 'e' && !extended_offset) {
2475 i = get_nonexisting_partition(0, 4);
2477 add_partition(i, EXTENDED);
2480 printf("Invalid partition number "
2481 "for type '%c'\n", c);
2492 for (i = 0; i < 3; i++)
2493 if (ptes[i].changed)
2494 ptes[3].changed = 1;
2495 for (i = 3; i < g_partitions; i++) {
2496 struct pte *pe = &ptes[i];
2499 write_part_table_flag(pe->sectorbuffer);
2500 write_sector(pe->offset, pe->sectorbuffer);
2504 else if (LABEL_IS_SGI) {
2505 /* no test on change? the printf below might be mistaken */
2508 else if (LABEL_IS_SUN) {
2511 for (i = 0; i < 8; i++)
2512 if (ptes[i].changed)
2518 printf("The partition table has been altered!\n\n");
2519 reread_partition_table(1);
2523 reread_partition_table(int leave)
2527 printf("Calling ioctl() to re-read partition table\n");
2529 /* sleep(2); Huh? */
2530 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2531 "WARNING: rereading partition table "
2532 "failed, kernel still uses old table");
2536 "\nWARNING: If you have created or modified any DOS 6.x\n"
2537 "partitions, please see the fdisk manual page for additional\n"
2542 if (ENABLE_FEATURE_CLEAN_UP)
2547 #endif /* FEATURE_FDISK_WRITABLE */
2549 #if ENABLE_FEATURE_FDISK_ADVANCED
2550 #define MAX_PER_LINE 16
2552 print_buffer(char *pbuffer)
2556 for (i = 0, l = 0; i < sector_size; i++, l++) {
2558 printf("0x%03X:", i);
2559 printf(" %02X", (unsigned char) pbuffer[i]);
2560 if (l == MAX_PER_LINE - 1) {
2575 printf("Device: %s\n", disk_device);
2576 if (LABEL_IS_SGI || LABEL_IS_SUN)
2577 print_buffer(MBRbuffer);
2579 for (i = 3; i < g_partitions; i++)
2580 print_buffer(ptes[i].sectorbuffer);
2585 move_begin(unsigned i)
2587 struct pte *pe = &ptes[i];
2588 struct partition *p = pe->part_table;
2589 sector_t new, first;
2591 if (warn_geometry())
2593 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2594 printf("Partition %u has no data area\n", i + 1);
2597 first = get_partition_start(pe);
2598 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2599 "New beginning of data") - pe->offset;
2601 if (new != get_nr_sects(p)) {
2602 first = get_nr_sects(p) + get_start_sect(p) - new;
2603 set_nr_sects(p, first);
2604 set_start_sect(p, new);
2616 c = tolower(read_nonempty("Expert command (m for help): "));
2624 move_begin(get_partition(0, g_partitions));
2627 user_cylinders = g_cylinders =
2628 read_int(1, g_cylinders, 1048576, 0,
2629 "Number of cylinders");
2631 sun_set_ncyl(g_cylinders);
2641 else if (LABEL_IS_SUN)
2643 else if (LABEL_IS_DOS)
2648 fix_partition_table_order();
2651 #if ENABLE_FEATURE_SGI_LABEL
2656 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2675 if (ENABLE_FEATURE_CLEAN_UP)
2682 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2683 "Number of sectors");
2684 if (dos_compatible_flag) {
2685 sector_offset = g_sectors;
2686 printf("Warning: setting sector offset for DOS "
2695 write_table(); /* does not return */
2699 sun_set_pcylcount();
2706 #endif /* ADVANCED mode */
2709 is_ide_cdrom_or_tape(const char *device)
2713 struct stat statbuf;
2716 /* No device was given explicitly, and we are trying some
2717 likely things. But opening /dev/hdc may produce errors like
2718 "hdc: tray open or drive not ready"
2719 if it happens to be a CD-ROM drive. It even happens that
2720 the process hangs on the attempt to read a music CD.
2721 So try to be careful. This only works since 2.1.73. */
2723 if (strncmp("/dev/hd", device, 7))
2726 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2727 procf = fopen_for_read(buf);
2728 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2729 is_ide = (!strncmp(buf, "cdrom", 5) ||
2730 !strncmp(buf, "tape", 4));
2732 /* Now when this proc file does not exist, skip the
2733 device when it is read-only. */
2734 if (stat(device, &statbuf) == 0)
2735 is_ide = ((statbuf.st_mode & 0222) == 0);
2744 open_list_and_close(const char *device, int user_specified)
2748 disk_device = device;
2749 if (setjmp(listingbuf))
2751 if (!user_specified)
2752 if (is_ide_cdrom_or_tape(device))
2755 /* Open disk_device, save file descriptor to dev_fd */
2757 gb = get_boot(TRY_ONLY);
2758 if (gb > 0) { /* I/O error */
2759 /* Ignore other errors, since we try IDE
2760 and SCSI hard disks which may not be
2761 installed on the system. */
2762 if (user_specified || errno == EACCES)
2763 bb_perror_msg("can't open '%s'", device);
2767 if (gb < 0) { /* no DOS signature */
2768 list_disk_geometry();
2771 #if ENABLE_FEATURE_OSF_LABEL
2772 if (bsd_trydev(device) < 0)
2774 printf("Disk %s doesn't contain a valid "
2775 "partition table\n", device);
2778 #if ENABLE_FEATURE_FDISK_WRITABLE
2779 if (!LABEL_IS_SUN && g_partitions > 4) {
2780 delete_partition(ext_index);
2788 /* for fdisk -l: try all things in /proc/partitions
2789 that look like a partition name (do not end in a digit) */
2791 list_devs_in_proc_partititons(void)
2794 char line[100], ptname[100], devname[120], *s;
2797 procpt = fopen_or_warn("/proc/partitions", "r");
2799 while (fgets(line, sizeof(line), procpt)) {
2800 if (sscanf(line, " %u %u %u %[^\n ]",
2801 &ma, &mi, &sz, ptname) != 4)
2803 for (s = ptname; *s; s++)
2807 sprintf(devname, "/dev/%s", ptname);
2808 open_list_and_close(devname, 0);
2810 #if ENABLE_FEATURE_CLEAN_UP
2815 #if ENABLE_FEATURE_FDISK_WRITABLE
2817 unknown_command(int c)
2819 printf("%c: unknown command\n", c);
2823 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2824 int fdisk_main(int argc, char **argv)
2829 * fdisk -l [-b sectorsize] [-u] device ...
2830 * fdisk -s [partition] ...
2831 * fdisk [-b sectorsize] [-u] device
2833 * Options -C, -H, -S set the geometry.
2837 close_dev_fd(); /* needed: fd 3 must not stay closed */
2839 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2840 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2841 §or_size, &user_cylinders, &user_heads, &user_sectors);
2844 if (opt & OPT_b) { // -b
2845 /* Ugly: this sector size is really per device,
2846 so cannot be combined with multiple disks,
2847 and the same goes for the C/H/S options.
2849 if (sector_size != 512 && sector_size != 1024
2850 && sector_size != 2048)
2853 user_set_sector_size = 1;
2855 if (user_heads <= 0 || user_heads >= 256)
2857 if (user_sectors <= 0 || user_sectors >= 64)
2860 display_in_cyl_units = 0; // -u
2862 #if ENABLE_FEATURE_FDISK_WRITABLE
2869 open_list_and_close(*argv, 1);
2872 /* we don't have device names, */
2873 /* use /proc/partitions instead */
2874 list_devs_in_proc_partititons();
2877 #if ENABLE_FEATURE_FDISK_WRITABLE
2881 #if ENABLE_FEATURE_FDISK_BLKSIZE
2888 for (j = 0; j < argc; j++) {
2889 unsigned long long size;
2890 fd = xopen(argv[j], O_RDONLY);
2891 size = bb_BLKGETSIZE_sectors(fd) / 2;
2894 printf("%llu\n", size);
2896 printf("%s: %llu\n", argv[j], size);
2902 #if ENABLE_FEATURE_FDISK_WRITABLE
2906 disk_device = argv[0];
2907 get_boot(OPEN_MAIN);
2910 /* OSF label, and no DOS label */
2911 printf("Detected an OSF/1 disklabel on %s, entering "
2912 "disklabel mode\n", disk_device);
2914 /*Why do we do this? It seems to be counter-intuitive*/
2915 current_label_type = LABEL_DOS;
2916 /* If we return we may want to make an empty DOS label? */
2922 c = tolower(read_nonempty("Command (m for help): "));
2926 toggle_active(get_partition(1, g_partitions));
2927 else if (LABEL_IS_SUN)
2928 toggle_sunflags(get_partition(1, g_partitions),
2930 else if (LABEL_IS_SGI)
2931 sgi_set_bootpartition(
2932 get_partition(1, g_partitions));
2938 printf("\nThe current boot file is: %s\n",
2939 sgi_get_bootfile());
2940 if (read_maybe_empty("Please enter the name of the "
2941 "new boot file: ") == '\n')
2942 printf("Boot file unchanged\n");
2944 sgi_set_bootfile(line_ptr);
2946 #if ENABLE_FEATURE_OSF_LABEL
2953 toggle_dos_compatibility_flag();
2954 else if (LABEL_IS_SUN)
2955 toggle_sunflags(get_partition(1, g_partitions),
2957 else if (LABEL_IS_SGI)
2958 sgi_set_swappartition(
2959 get_partition(1, g_partitions));
2966 /* If sgi_label then don't use get_existing_partition,
2967 let the user select a partition, since
2968 get_existing_partition() only works for Linux-like
2970 if (!LABEL_IS_SGI) {
2971 j = get_existing_partition(1, g_partitions);
2973 j = get_partition(1, g_partitions);
2976 delete_partition(j);
2985 list_types(get_sys_types());
3000 if (ENABLE_FEATURE_CLEAN_UP)
3005 #if ENABLE_FEATURE_SUN_LABEL
3019 write_table(); /* does not return */
3021 #if ENABLE_FEATURE_FDISK_ADVANCED
3024 printf("\n\tSorry, no experts menu for SGI "
3025 "partition tables available\n\n");
3036 #endif /* FEATURE_FDISK_WRITABLE */