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)
21 /* Looks like someone forgot to add this to config system */
22 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
23 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
24 # define IF_FEATURE_FDISK_BLKSIZE(a)
27 #define DEFAULT_SECTOR_SIZE 512
28 #define DEFAULT_SECTOR_SIZE_STR "512"
29 #define MAX_SECTOR_SIZE 2048
30 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
31 #define MAXIMUM_PARTS 60
33 #define ACTIVE_FLAG 0x80
36 #define WIN98_EXTENDED 0x0f
37 #define LINUX_PARTITION 0x81
38 #define LINUX_SWAP 0x82
39 #define LINUX_NATIVE 0x83
40 #define LINUX_EXTENDED 0x85
41 #define LINUX_LVM 0x8e
42 #define LINUX_RAID 0xfd
52 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
56 typedef unsigned long long ullong;
57 /* Used for sector numbers. Partition formats we know
58 * do not support more than 2^32 sectors
60 typedef uint32_t sector_t;
61 #if UINT_MAX == 4294967295
63 #elif ULONG_MAX == 4294967295
66 # error Cant detect sizeof(uint32_t)
71 unsigned char sectors;
72 unsigned short cylinders;
76 #define HDIO_GETGEO 0x0301 /* get device geometry */
78 static const char msg_building_new_label[] ALIGN1 =
79 "Building a new %s. Changes will remain in memory only,\n"
80 "until you decide to write them. After that the previous content\n"
81 "won't be recoverable.\n\n";
83 static const char msg_part_already_defined[] ALIGN1 =
84 "Partition %u is already defined, delete it before re-adding\n";
88 unsigned char boot_ind; /* 0x80 - active */
89 unsigned char head; /* starting head */
90 unsigned char sector; /* starting sector */
91 unsigned char cyl; /* starting cylinder */
92 unsigned char sys_ind; /* what partition type */
93 unsigned char end_head; /* end head */
94 unsigned char end_sector; /* end sector */
95 unsigned char end_cyl; /* end cylinder */
96 unsigned char start4[4]; /* starting sector counting from 0 */
97 unsigned char size4[4]; /* nr of sectors in partition */
100 static const char unable_to_open[] ALIGN1 = "can't open '%s'";
101 static const char unable_to_read[] ALIGN1 = "can't read from %s";
102 static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
105 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
108 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
110 #if ENABLE_FEATURE_SUN_LABEL
111 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
112 #define STATIC_SUN static
114 #define LABEL_IS_SUN 0
115 #define STATIC_SUN extern
118 #if ENABLE_FEATURE_SGI_LABEL
119 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
120 #define STATIC_SGI static
122 #define LABEL_IS_SGI 0
123 #define STATIC_SGI extern
126 #if ENABLE_FEATURE_AIX_LABEL
127 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
128 #define STATIC_AIX static
130 #define LABEL_IS_AIX 0
131 #define STATIC_AIX extern
134 #if ENABLE_FEATURE_OSF_LABEL
135 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
136 #define STATIC_OSF static
138 #define LABEL_IS_OSF 0
139 #define STATIC_OSF extern
142 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
144 static void update_units(void);
145 #if ENABLE_FEATURE_FDISK_WRITABLE
146 static void change_units(void);
147 static void reread_partition_table(int leave);
148 static void delete_partition(int i);
149 static unsigned get_partition(int warn, unsigned max);
150 static void list_types(const char *const *sys);
151 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
153 static const char *partition_type(unsigned char type);
154 static void get_geometry(void);
155 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
156 static int get_boot(enum action what);
158 static int get_boot(void);
164 static sector_t get_start_sect(const struct partition *p);
165 static sector_t get_nr_sects(const struct partition *p);
168 * per partition table entry data
170 * The four primary partitions have the same sectorbuffer (MBRbuffer)
171 * and have NULL ext_pointer.
172 * Each logical partition table entry has two pointers, one for the
173 * partition and one link to the next one.
176 struct partition *part_table; /* points into sectorbuffer */
177 struct partition *ext_pointer; /* points into sectorbuffer */
178 sector_t offset; /* disk sector number */
179 char *sectorbuffer; /* disk sector contents */
180 #if ENABLE_FEATURE_FDISK_WRITABLE
181 char changed; /* boolean */
185 /* DOS partition types */
187 static const char *const i386_sys_types[] = {
191 "\x05" "Extended", /* DOS 3.3+ extended partition */
192 "\x06" "FAT16", /* DOS 16-bit >=32M */
193 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
194 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
195 "\x0b" "Win95 FAT32",
196 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
197 "\x0e" "Win95 FAT16 (LBA)",
198 "\x0f" "Win95 Ext'd (LBA)",
199 "\x11" "Hidden FAT12",
200 "\x12" "Compaq diagnostics",
201 "\x14" "Hidden FAT16 <32M",
202 "\x16" "Hidden FAT16",
203 "\x17" "Hidden HPFS/NTFS",
204 "\x1b" "Hidden Win95 FAT32",
205 "\x1c" "Hidden W95 FAT32 (LBA)",
206 "\x1e" "Hidden W95 FAT16 (LBA)",
207 "\x3c" "Part.Magic recovery",
208 "\x41" "PPC PReP Boot",
210 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
211 "\x80" "Old Minix", /* Minix 1.4a and earlier */
212 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
213 "\x82" "Linux swap", /* also Solaris */
215 "\x84" "OS/2 hidden C: drive",
216 "\x85" "Linux extended",
217 "\x86" "NTFS volume set",
218 "\x87" "NTFS volume set",
220 "\x9f" "BSD/OS", /* BSDI */
221 "\xa0" "Thinkpad hibernation",
222 "\xa5" "FreeBSD", /* various BSD flavours */
226 "\xab" "Darwin boot",
229 "\xbe" "Solaris boot",
231 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
232 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
233 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
234 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
235 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
236 autodetect using persistent
238 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
241 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
242 "\x09" "AIX bootable", /* AIX data or Coherent */
244 "\x18" "AST SmartSleep",
247 "\x40" "Venix 80286",
249 "\x4e" "QNX4.x 2nd part",
250 "\x4f" "QNX4.x 3rd part",
252 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
253 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
254 "\x53" "OnTrack DM6 Aux3",
258 "\x5c" "Priam Edisk",
260 "\x64" "Novell Netware 286",
261 "\x65" "Novell Netware 386",
262 "\x70" "DiskSecure Multi-Boot",
265 "\x94" "Amoeba BBT", /* (bad block table) */
267 "\xbb" "Boot Wizard hidden",
268 "\xc1" "DRDOS/sec (FAT-12)",
269 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
270 "\xc6" "DRDOS/sec (FAT-16)",
272 "\xda" "Non-FS data",
273 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
274 Concurrent DOS or CTOS */
275 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
276 "\xdf" "BootIt", /* BootIt EMBRM */
277 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
278 extended partition */
279 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
280 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
281 partition < 1024 cyl. */
283 "\xf4" "SpeedStor", /* SpeedStor large partition */
284 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
285 "\xff" "BBT", /* Xenix Bad Block Table */
291 dev_fd = 3 /* the disk */
298 const char *disk_device;
299 int g_partitions; // = 4; /* maximum partition + 1 */
300 unsigned units_per_sector; // = 1;
301 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
302 unsigned user_set_sector_size;
303 unsigned sector_offset; // = 1;
304 unsigned g_heads, g_sectors, g_cylinders;
305 smallint /* enum label_type */ current_label_type;
306 smallint display_in_cyl_units; // = 1;
307 #if ENABLE_FEATURE_OSF_LABEL
308 smallint possibly_osf_label;
311 smallint listing; /* no aborts for fdisk -l */
312 smallint dos_compatible_flag; // = 1;
313 #if ENABLE_FEATURE_FDISK_WRITABLE
315 smallint nowarn; /* no warnings for fdisk -l/-s */
317 int ext_index; /* the prime extended partition */
318 unsigned user_cylinders, user_heads, user_sectors;
319 unsigned pt_heads, pt_sectors;
320 unsigned kern_heads, kern_sectors;
321 sector_t extended_offset; /* offset of link pointers */
322 sector_t total_number_of_sectors;
325 char line_buffer[80];
326 char partname_buffer[80];
327 /* Raw disk label. For DOS-type partition tables the MBR,
328 * with descriptions of the primary partitions. */
329 char MBRbuffer[MAX_SECTOR_SIZE];
330 /* Partition tables */
331 struct pte ptes[MAXIMUM_PARTS];
333 #define G (*ptr_to_globals)
334 #define line_ptr (G.line_ptr )
335 #define disk_device (G.disk_device )
336 #define g_partitions (G.g_partitions )
337 #define units_per_sector (G.units_per_sector )
338 #define sector_size (G.sector_size )
339 #define user_set_sector_size (G.user_set_sector_size)
340 #define sector_offset (G.sector_offset )
341 #define g_heads (G.g_heads )
342 #define g_sectors (G.g_sectors )
343 #define g_cylinders (G.g_cylinders )
344 #define current_label_type (G.current_label_type )
345 #define display_in_cyl_units (G.display_in_cyl_units)
346 #define possibly_osf_label (G.possibly_osf_label )
347 #define listing (G.listing )
348 #define dos_compatible_flag (G.dos_compatible_flag )
349 #define nowarn (G.nowarn )
350 #define ext_index (G.ext_index )
351 #define user_cylinders (G.user_cylinders )
352 #define user_heads (G.user_heads )
353 #define user_sectors (G.user_sectors )
354 #define pt_heads (G.pt_heads )
355 #define pt_sectors (G.pt_sectors )
356 #define kern_heads (G.kern_heads )
357 #define kern_sectors (G.kern_sectors )
358 #define extended_offset (G.extended_offset )
359 #define total_number_of_sectors (G.total_number_of_sectors)
360 #define listingbuf (G.listingbuf )
361 #define line_buffer (G.line_buffer )
362 #define partname_buffer (G.partname_buffer)
363 #define MBRbuffer (G.MBRbuffer )
364 #define ptes (G.ptes )
365 #define INIT_G() do { \
366 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
367 sector_size = DEFAULT_SECTOR_SIZE; \
370 display_in_cyl_units = 1; \
371 units_per_sector = 1; \
372 dos_compatible_flag = 1; \
376 /* TODO: move to libbb? */
377 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
378 * disks > 2^32 sectors
380 static sector_t bb_BLKGETSIZE_sectors(int fd)
383 unsigned long longsectors;
385 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
386 /* Got bytes, convert to 512 byte sectors */
388 if (v64 != (sector_t)v64) {
390 /* Not only DOS, but all other partition tables
391 * we support can't record more than 32 bit
392 * sector counts or offsets
394 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
399 /* Needs temp of type long */
400 if (ioctl(fd, BLKGETSIZE, &longsectors))
402 if (sizeof(long) > sizeof(sector_t)
403 && longsectors != (sector_t)longsectors
411 #define IS_EXTENDED(i) \
412 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
414 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
416 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
418 #define pt_offset(b, n) \
419 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
421 #define sector(s) ((s) & 0x3f)
423 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
425 #define hsc2sector(h,s,c) \
426 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
428 #define set_hsc(h,s,c,sector) \
430 s = sector % g_sectors + 1; \
431 sector /= g_sectors; \
432 h = sector % g_heads; \
435 s |= (sector >> 2) & 0xc0; \
441 /* Not really closing, but making sure it is open, and to harmless place */
442 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
445 #if ENABLE_FEATURE_FDISK_WRITABLE
446 /* Read line; return 0 or first printable char */
448 read_line(const char *prompt)
452 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
454 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
456 if (line_buffer[sz-1] == '\n')
457 line_buffer[--sz] = '\0';
459 line_ptr = line_buffer;
460 while (*line_ptr && !isgraph(*line_ptr))
467 * Return partition name - uses static storage
470 partname(const char *dev, int pno, int lth)
477 bufp = partname_buffer;
478 bufsiz = sizeof(partname_buffer);
483 if (isdigit(dev[w-1]))
486 /* devfs kludge - note: fdisk partition names are not supposed
487 to equal kernel names, so there is no reason to do this */
488 if (strcmp(dev + w - 4, "disc") == 0) {
496 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
497 lth-wp-2, w, dev, p, pno);
499 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
504 #if ENABLE_FEATURE_FDISK_WRITABLE
506 set_all_unchanged(void)
510 for (i = 0; i < MAXIMUM_PARTS; i++)
514 static ALWAYS_INLINE void
519 #endif /* FEATURE_FDISK_WRITABLE */
521 static ALWAYS_INLINE struct partition *
522 get_part_table(int i)
524 return ptes[i].part_table;
529 { /* n==1: use singular */
531 return display_in_cyl_units ? "cylinder" : "sector";
532 return display_in_cyl_units ? "cylinders" : "sectors";
536 valid_part_table_flag(const char *mbuffer)
538 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
541 #if ENABLE_FEATURE_FDISK_WRITABLE
542 static ALWAYS_INLINE void
543 write_part_table_flag(char *b)
550 read_nonempty(const char *mesg)
552 while (!read_line(mesg))
558 read_maybe_empty(const char *mesg)
560 if (!read_line(mesg)) {
561 line_ptr = line_buffer;
569 read_hex(const char *const *sys)
573 read_nonempty("Hex code (type L to list codes): ");
574 if (*line_ptr == 'l' || *line_ptr == 'L') {
578 v = bb_strtoul(line_ptr, NULL, 16);
580 /* Bad input also triggers this */
585 #endif /* FEATURE_FDISK_WRITABLE */
587 static void fdisk_fatal(const char *why)
591 longjmp(listingbuf, 1);
593 bb_error_msg_and_die(why, disk_device);
597 seek_sector(sector_t secno)
599 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
600 off64_t off = (off64_t)secno * sector_size;
601 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
602 fdisk_fatal(unable_to_seek);
604 uint64_t off = (uint64_t)secno * sector_size;
605 if (off > MAXINT(off_t)
606 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
608 fdisk_fatal(unable_to_seek);
613 #if ENABLE_FEATURE_FDISK_WRITABLE
615 write_sector(sector_t secno, const void *buf)
618 xwrite(dev_fd, buf, sector_size);
623 #include "fdisk_aix.c"
626 unsigned char info[128]; /* Informative text string */
627 unsigned char spare0[14];
629 unsigned char spare1;
631 unsigned char spare2;
634 unsigned char spare1[246]; /* Boot information etc. */
635 unsigned short rspeed; /* Disk rotational speed */
636 unsigned short pcylcount; /* Physical cylinder count */
637 unsigned short sparecyl; /* extra sects per cylinder */
638 unsigned char spare2[4]; /* More magic... */
639 unsigned short ilfact; /* Interleave factor */
640 unsigned short ncyl; /* Data cylinder count */
641 unsigned short nacyl; /* Alt. cylinder count */
642 unsigned short ntrks; /* Tracks per cylinder */
643 unsigned short nsect; /* Sectors per track */
644 unsigned char spare3[4]; /* Even more magic... */
645 struct sun_partinfo {
646 uint32_t start_cylinder;
647 uint32_t num_sectors;
649 unsigned short magic; /* Magic number */
650 unsigned short csum; /* Label xor'd checksum */
652 #define sunlabel ((sun_partition *)MBRbuffer)
653 STATIC_OSF void bsd_select(void);
654 STATIC_OSF void xbsd_print_disklabel(int);
655 #include "fdisk_osf.c"
657 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
659 fdisk_swap16(uint16_t x)
661 return (x << 8) | (x >> 8);
665 fdisk_swap32(uint32_t x)
668 ((x & 0xFF00) << 8) |
669 ((x & 0xFF0000) >> 8) |
674 STATIC_SGI const char *const sgi_sys_types[];
675 STATIC_SGI unsigned sgi_get_num_sectors(int i);
676 STATIC_SGI int sgi_get_sysid(int i);
677 STATIC_SGI void sgi_delete_partition(int i);
678 STATIC_SGI void sgi_change_sysid(int i, int sys);
679 STATIC_SGI void sgi_list_table(int xtra);
680 #if ENABLE_FEATURE_FDISK_ADVANCED
681 STATIC_SGI void sgi_set_xcyl(void);
683 STATIC_SGI int verify_sgi(int verbose);
684 STATIC_SGI void sgi_add_partition(int n, int sys);
685 STATIC_SGI void sgi_set_swappartition(int i);
686 STATIC_SGI const char *sgi_get_bootfile(void);
687 STATIC_SGI void sgi_set_bootfile(const char* aFile);
688 STATIC_SGI void create_sgiinfo(void);
689 STATIC_SGI void sgi_write_table(void);
690 STATIC_SGI void sgi_set_bootpartition(int i);
691 #include "fdisk_sgi.c"
693 STATIC_SUN const char *const sun_sys_types[];
694 STATIC_SUN void sun_delete_partition(int i);
695 STATIC_SUN void sun_change_sysid(int i, int sys);
696 STATIC_SUN void sun_list_table(int xtra);
697 STATIC_SUN void add_sun_partition(int n, int sys);
698 #if ENABLE_FEATURE_FDISK_ADVANCED
699 STATIC_SUN void sun_set_alt_cyl(void);
700 STATIC_SUN void sun_set_ncyl(int cyl);
701 STATIC_SUN void sun_set_xcyl(void);
702 STATIC_SUN void sun_set_ilfact(void);
703 STATIC_SUN void sun_set_rspeed(void);
704 STATIC_SUN void sun_set_pcylcount(void);
706 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
707 STATIC_SUN void verify_sun(void);
708 STATIC_SUN void sun_write_table(void);
709 #include "fdisk_sun.c"
712 #if ENABLE_FEATURE_FDISK_WRITABLE
713 /* start_sect and nr_sects are stored little endian on all machines */
714 /* moreover, they are not aligned correctly */
716 store4_little_endian(unsigned char *cp, unsigned val)
723 #endif /* FEATURE_FDISK_WRITABLE */
726 read4_little_endian(const unsigned char *cp)
728 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
731 #if ENABLE_FEATURE_FDISK_WRITABLE
733 set_start_sect(struct partition *p, unsigned start_sect)
735 store4_little_endian(p->start4, start_sect);
740 get_start_sect(const struct partition *p)
742 return read4_little_endian(p->start4);
745 #if ENABLE_FEATURE_FDISK_WRITABLE
747 set_nr_sects(struct partition *p, unsigned nr_sects)
749 store4_little_endian(p->size4, nr_sects);
754 get_nr_sects(const struct partition *p)
756 return read4_little_endian(p->size4);
759 /* Allocate a buffer and read a partition table sector */
761 read_pte(struct pte *pe, sector_t offset)
764 pe->sectorbuffer = xzalloc(sector_size);
766 /* xread would make us abort - bad for fdisk -l */
767 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
768 fdisk_fatal(unable_to_read);
769 #if ENABLE_FEATURE_FDISK_WRITABLE
772 pe->part_table = pe->ext_pointer = NULL;
776 get_partition_start(const struct pte *pe)
778 return pe->offset + get_start_sect(pe->part_table);
781 #if ENABLE_FEATURE_FDISK_WRITABLE
783 * Avoid warning about DOS partitions when no DOS partition was changed.
784 * Here a heuristic "is probably dos partition".
785 * We might also do the opposite and warn in all cases except
786 * for "is probably nondos partition".
790 is_dos_partition(int t)
792 return (t == 1 || t == 4 || t == 6 ||
793 t == 0x0b || t == 0x0c || t == 0x0e ||
794 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
795 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
796 t == 0xc1 || t == 0xc4 || t == 0xc6);
803 puts("Command Action");
805 puts("a\ttoggle a read only flag"); /* sun */
806 puts("b\tedit bsd disklabel");
807 puts("c\ttoggle the mountable flag"); /* sun */
808 puts("d\tdelete a partition");
809 puts("l\tlist known partition types");
810 puts("n\tadd a new partition");
811 puts("o\tcreate a new empty DOS partition table");
812 puts("p\tprint the partition table");
813 puts("q\tquit without saving changes");
814 puts("s\tcreate a new empty Sun disklabel"); /* sun */
815 puts("t\tchange a partition's system id");
816 puts("u\tchange display/entry units");
817 puts("v\tverify the partition table");
818 puts("w\twrite table to disk and exit");
819 #if ENABLE_FEATURE_FDISK_ADVANCED
820 puts("x\textra functionality (experts only)");
822 } else if (LABEL_IS_SGI) {
823 puts("a\tselect bootable partition"); /* sgi flavour */
824 puts("b\tedit bootfile entry"); /* sgi */
825 puts("c\tselect sgi swap partition"); /* sgi flavour */
826 puts("d\tdelete a partition");
827 puts("l\tlist known partition types");
828 puts("n\tadd a new partition");
829 puts("o\tcreate a new empty DOS partition table");
830 puts("p\tprint the partition table");
831 puts("q\tquit without saving changes");
832 puts("s\tcreate a new empty Sun disklabel"); /* sun */
833 puts("t\tchange a partition's system id");
834 puts("u\tchange display/entry units");
835 puts("v\tverify the partition table");
836 puts("w\twrite table to disk and exit");
837 } else if (LABEL_IS_AIX) {
838 puts("o\tcreate a new empty DOS partition table");
839 puts("q\tquit without saving changes");
840 puts("s\tcreate a new empty Sun disklabel"); /* sun */
842 puts("a\ttoggle a bootable flag");
843 puts("b\tedit bsd disklabel");
844 puts("c\ttoggle the dos compatibility flag");
845 puts("d\tdelete a partition");
846 puts("l\tlist known partition types");
847 puts("n\tadd a new partition");
848 puts("o\tcreate a new empty DOS partition table");
849 puts("p\tprint the partition table");
850 puts("q\tquit without saving changes");
851 puts("s\tcreate a new empty Sun disklabel"); /* sun */
852 puts("t\tchange a partition's system id");
853 puts("u\tchange display/entry units");
854 puts("v\tverify the partition table");
855 puts("w\twrite table to disk and exit");
856 #if ENABLE_FEATURE_FDISK_ADVANCED
857 puts("x\textra functionality (experts only)");
861 #endif /* FEATURE_FDISK_WRITABLE */
864 #if ENABLE_FEATURE_FDISK_ADVANCED
868 puts("Command Action");
870 puts("a\tchange number of alternate cylinders"); /*sun*/
871 puts("c\tchange number of cylinders");
872 puts("d\tprint the raw data in the partition table");
873 puts("e\tchange number of extra sectors per cylinder");/*sun*/
874 puts("h\tchange number of heads");
875 puts("i\tchange interleave factor"); /*sun*/
876 puts("o\tchange rotation speed (rpm)"); /*sun*/
877 puts("p\tprint the partition table");
878 puts("q\tquit without saving changes");
879 puts("r\treturn to main menu");
880 puts("s\tchange number of sectors/track");
881 puts("v\tverify the partition table");
882 puts("w\twrite table to disk and exit");
883 puts("y\tchange number of physical cylinders"); /*sun*/
884 } else if (LABEL_IS_SGI) {
885 puts("b\tmove beginning of data in a partition"); /* !sun */
886 puts("c\tchange number of cylinders");
887 puts("d\tprint the raw data in the partition table");
888 puts("e\tlist extended partitions"); /* !sun */
889 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
890 puts("h\tchange number of heads");
891 puts("p\tprint the partition table");
892 puts("q\tquit without saving changes");
893 puts("r\treturn to main menu");
894 puts("s\tchange number of sectors/track");
895 puts("v\tverify the partition table");
896 puts("w\twrite table to disk and exit");
897 } else if (LABEL_IS_AIX) {
898 puts("b\tmove beginning of data in a partition"); /* !sun */
899 puts("c\tchange number of cylinders");
900 puts("d\tprint the raw data in the partition table");
901 puts("e\tlist extended partitions"); /* !sun */
902 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
903 puts("h\tchange number of heads");
904 puts("p\tprint the partition table");
905 puts("q\tquit without saving changes");
906 puts("r\treturn to main menu");
907 puts("s\tchange number of sectors/track");
908 puts("v\tverify the partition table");
909 puts("w\twrite table to disk and exit");
911 puts("b\tmove beginning of data in a partition"); /* !sun */
912 puts("c\tchange number of cylinders");
913 puts("d\tprint the raw data in the partition table");
914 puts("e\tlist extended partitions"); /* !sun */
915 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
916 #if ENABLE_FEATURE_SGI_LABEL
917 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
919 puts("h\tchange number of heads");
920 puts("p\tprint the partition table");
921 puts("q\tquit without saving changes");
922 puts("r\treturn to main menu");
923 puts("s\tchange number of sectors/track");
924 puts("v\tverify the partition table");
925 puts("w\twrite table to disk and exit");
928 #endif /* ADVANCED mode */
930 #if ENABLE_FEATURE_FDISK_WRITABLE
931 static const char *const *
935 LABEL_IS_SUN ? sun_sys_types :
936 LABEL_IS_SGI ? sgi_sys_types :
940 #define get_sys_types() i386_sys_types
941 #endif /* FEATURE_FDISK_WRITABLE */
944 partition_type(unsigned char type)
947 const char *const *types = get_sys_types();
949 for (i = 0; types[i]; i++)
950 if ((unsigned char)types[i][0] == type)
957 #if ENABLE_FEATURE_FDISK_WRITABLE
961 return LABEL_IS_SUN ? sunlabel->infos[i].id :
962 (LABEL_IS_SGI ? sgi_get_sysid(i) :
963 ptes[i].part_table->sys_ind);
967 list_types(const char *const *sys)
972 unsigned done, next, size;
975 for (size = 0; sys[size]; size++)
979 for (i = COLS-1; i >= 0; i--) {
980 done += (size + i - done) / (i + 1);
981 last[COLS-1 - i] = done;
986 printf("%c%2x %-22.22s", i ? ' ' : '\n',
987 (unsigned char)sys[next][0],
989 next = last[i++] + done;
990 if (i >= COLS || next >= last[i]) {
994 } while (done < last[0]);
997 #endif /* FEATURE_FDISK_WRITABLE */
1000 is_cleared_partition(const struct partition *p)
1002 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
1003 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
1004 get_start_sect(p) || get_nr_sects(p));
1008 clear_partition(struct partition *p)
1012 memset(p, 0, sizeof(struct partition));
1015 #if ENABLE_FEATURE_FDISK_WRITABLE
1017 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1019 struct partition *p;
1023 p = ptes[i].ext_pointer;
1024 offset = extended_offset;
1026 p = ptes[i].part_table;
1027 offset = ptes[i].offset;
1031 set_start_sect(p, start - offset);
1032 set_nr_sects(p, stop - start + 1);
1033 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1034 start = g_heads * g_sectors * 1024 - 1;
1035 set_hsc(p->head, p->sector, p->cyl, start);
1036 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1037 stop = g_heads * g_sectors * 1024 - 1;
1038 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1039 ptes[i].changed = 1;
1046 if (g_heads && g_sectors && g_cylinders)
1049 printf("Unknown value(s) for:");
1055 printf(" cylinders");
1057 #if ENABLE_FEATURE_FDISK_WRITABLE
1058 " (settable in the extra functions menu)"
1067 int cyl_units = g_heads * g_sectors;
1069 if (display_in_cyl_units && cyl_units)
1070 units_per_sector = cyl_units;
1072 units_per_sector = 1; /* in sectors */
1075 #if ENABLE_FEATURE_FDISK_WRITABLE
1077 warn_cylinders(void)
1079 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1081 "The number of cylinders for this disk is set to %u.\n"
1082 "There is nothing wrong with that, but this is larger than 1024,\n"
1083 "and could in certain setups cause problems with:\n"
1084 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1085 "2) booting and partitioning software from other OSs\n"
1086 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1092 read_extended(int ext)
1096 struct partition *p, *q;
1100 pex->ext_pointer = pex->part_table;
1102 p = pex->part_table;
1103 if (!get_start_sect(p)) {
1104 printf("Bad offset in primary extended partition\n");
1108 while (IS_EXTENDED(p->sys_ind)) {
1109 struct pte *pe = &ptes[g_partitions];
1111 if (g_partitions >= MAXIMUM_PARTS) {
1112 /* This is not a Linux restriction, but
1113 this program uses arrays of size MAXIMUM_PARTS.
1114 Do not try to 'improve' this test. */
1115 struct pte *pre = &ptes[g_partitions - 1];
1116 #if ENABLE_FEATURE_FDISK_WRITABLE
1117 printf("Warning: deleting partitions after %u\n",
1121 clear_partition(pre->ext_pointer);
1125 read_pte(pe, extended_offset + get_start_sect(p));
1127 if (!extended_offset)
1128 extended_offset = get_start_sect(p);
1130 q = p = pt_offset(pe->sectorbuffer, 0);
1131 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1132 if (IS_EXTENDED(p->sys_ind)) {
1133 if (pe->ext_pointer)
1134 printf("Warning: extra link "
1135 "pointer in partition table"
1136 " %u\n", g_partitions + 1);
1138 pe->ext_pointer = p;
1139 } else if (p->sys_ind) {
1141 printf("Warning: ignoring extra "
1142 "data in partition table"
1143 " %u\n", g_partitions + 1);
1149 /* very strange code here... */
1150 if (!pe->part_table) {
1151 if (q != pe->ext_pointer)
1154 pe->part_table = q + 1;
1156 if (!pe->ext_pointer) {
1157 if (q != pe->part_table)
1158 pe->ext_pointer = q;
1160 pe->ext_pointer = q + 1;
1163 p = pe->ext_pointer;
1167 #if ENABLE_FEATURE_FDISK_WRITABLE
1168 /* remove empty links */
1170 for (i = 4; i < g_partitions; i++) {
1171 struct pte *pe = &ptes[i];
1173 if (!get_nr_sects(pe->part_table)
1174 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1176 printf("Omitting empty partition (%u)\n", i+1);
1177 delete_partition(i);
1178 goto remove; /* numbering changed */
1184 #if ENABLE_FEATURE_FDISK_WRITABLE
1186 create_doslabel(void)
1190 printf(msg_building_new_label, "DOS disklabel");
1192 current_label_type = LABEL_DOS;
1194 #if ENABLE_FEATURE_OSF_LABEL
1195 possibly_osf_label = 0;
1199 for (i = 510-64; i < 510; i++)
1201 write_part_table_flag(MBRbuffer);
1202 extended_offset = 0;
1203 set_all_unchanged();
1205 get_boot(CREATE_EMPTY_DOS);
1207 #endif /* FEATURE_FDISK_WRITABLE */
1210 get_sectorsize(void)
1212 if (!user_set_sector_size) {
1214 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1216 if (sector_size != DEFAULT_SECTOR_SIZE)
1217 printf("Note: sector size is %u "
1218 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1224 get_kernel_geometry(void)
1226 struct hd_geometry geometry;
1228 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1229 kern_heads = geometry.heads;
1230 kern_sectors = geometry.sectors;
1231 /* never use geometry.cylinders - it is truncated */
1236 get_partition_table_geometry(void)
1238 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1239 struct partition *p;
1240 int i, h, s, hh, ss;
1244 if (!(valid_part_table_flag((char*)bufp)))
1248 for (i = 0; i < 4; i++) {
1249 p = pt_offset(bufp, i);
1250 if (p->sys_ind != 0) {
1251 h = p->end_head + 1;
1252 s = (p->end_sector & 077);
1257 } else if (hh != h || ss != s)
1262 if (!first && !bad) {
1274 sec_fac = sector_size / 512;
1275 #if ENABLE_FEATURE_SUN_LABEL
1276 guess_device_type();
1278 g_heads = g_cylinders = g_sectors = 0;
1279 kern_heads = kern_sectors = 0;
1280 pt_heads = pt_sectors = 0;
1282 get_kernel_geometry();
1283 get_partition_table_geometry();
1285 g_heads = user_heads ? user_heads :
1286 pt_heads ? pt_heads :
1287 kern_heads ? kern_heads : 255;
1288 g_sectors = user_sectors ? user_sectors :
1289 pt_sectors ? pt_sectors :
1290 kern_sectors ? kern_sectors : 63;
1291 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1294 if (dos_compatible_flag)
1295 sector_offset = g_sectors;
1297 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1299 g_cylinders = user_cylinders;
1303 * Opens disk_device and optionally reads MBR.
1304 * FIXME: document what each 'what' value will do!
1306 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1307 * 0: found or created label
1310 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1311 static int get_boot(enum action what)
1313 static int get_boot(void)
1314 #define get_boot(what) get_boot()
1320 for (i = 0; i < 4; i++) {
1321 struct pte *pe = &ptes[i];
1322 pe->part_table = pt_offset(MBRbuffer, i);
1323 pe->ext_pointer = NULL;
1325 pe->sectorbuffer = MBRbuffer;
1326 #if ENABLE_FEATURE_FDISK_WRITABLE
1327 pe->changed = (what == CREATE_EMPTY_DOS);
1331 #if ENABLE_FEATURE_FDISK_WRITABLE
1332 // ALERT! highly idiotic design!
1333 // We end up here when we call get_boot() recursively
1334 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1335 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1336 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1337 // So skip opening device _again_...
1338 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1341 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1344 fd = open(disk_device, O_RDONLY);
1346 if (what == TRY_ONLY)
1348 fdisk_fatal(unable_to_open);
1350 printf("'%s' is opened for read only\n", disk_device);
1352 xmove_fd(fd, dev_fd);
1353 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1354 if (what == TRY_ONLY) {
1358 fdisk_fatal(unable_to_read);
1361 fd = open(disk_device, O_RDONLY);
1364 if (512 != full_read(fd, MBRbuffer, 512)) {
1368 xmove_fd(fd, dev_fd);
1374 #if ENABLE_FEATURE_SUN_LABEL
1375 if (check_sun_label())
1378 #if ENABLE_FEATURE_SGI_LABEL
1379 if (check_sgi_label())
1382 #if ENABLE_FEATURE_AIX_LABEL
1383 if (check_aix_label())
1386 #if ENABLE_FEATURE_OSF_LABEL
1387 if (check_osf_label()) {
1388 possibly_osf_label = 1;
1389 if (!valid_part_table_flag(MBRbuffer)) {
1390 current_label_type = LABEL_OSF;
1393 printf("This disk has both DOS and BSD magic.\n"
1394 "Give the 'b' command to go to BSD mode.\n");
1398 #if !ENABLE_FEATURE_FDISK_WRITABLE
1399 if (!valid_part_table_flag(MBRbuffer))
1402 if (!valid_part_table_flag(MBRbuffer)) {
1403 if (what == OPEN_MAIN) {
1404 printf("Device contains neither a valid DOS "
1405 "partition table, nor Sun, SGI or OSF "
1408 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1418 #endif /* FEATURE_FDISK_WRITABLE */
1421 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1424 for (i = 0; i < 4; i++) {
1425 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1426 if (g_partitions != 4)
1427 printf("Ignoring extra extended "
1428 "partition %u\n", i + 1);
1434 for (i = 3; i < g_partitions; i++) {
1435 struct pte *pe = &ptes[i];
1436 if (!valid_part_table_flag(pe->sectorbuffer)) {
1437 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1438 "table %u will be corrected by w(rite)\n",
1439 pe->sectorbuffer[510],
1440 pe->sectorbuffer[511],
1442 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1449 #if ENABLE_FEATURE_FDISK_WRITABLE
1451 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1452 * If the user hits Enter, DFLT is returned.
1453 * Answers like +10 are interpreted as offsets from BASE.
1455 * There is no default if DFLT is not between LOW and HIGH.
1458 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1462 const char *fmt = "%s (%u-%u, default %u): ";
1464 if (dflt < low || dflt > high) {
1465 fmt = "%s (%u-%u): ";
1470 int use_default = default_ok;
1472 /* ask question and read answer */
1474 printf(fmt, mesg, low, high, dflt);
1475 read_maybe_empty("");
1476 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1477 && *line_ptr != '-' && *line_ptr != '+');
1479 if (*line_ptr == '+' || *line_ptr == '-') {
1480 int minus = (*line_ptr == '-');
1483 value = atoi(line_ptr + 1);
1485 /* (1) if 2nd char is digit, use_default = 0.
1486 * (2) move line_ptr to first non-digit. */
1487 while (isdigit(*++line_ptr))
1490 switch (*line_ptr) {
1493 if (!display_in_cyl_units)
1494 value *= g_heads * g_sectors;
1508 absolute = 1000000000;
1517 bytes = (ullong) value * absolute;
1518 unit = sector_size * units_per_sector;
1519 bytes += unit/2; /* round */
1527 value = atoi(line_ptr);
1528 while (isdigit(*line_ptr)) {
1535 printf("Using default value %u\n", value);
1537 if (value >= low && value <= high)
1539 printf("Value is out of range\n");
1545 get_partition(int warn, unsigned max)
1550 i = read_int(1, 0, max, 0, "Partition number") - 1;
1554 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1555 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1556 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1558 printf("Warning: partition %u has empty type\n", i+1);
1565 get_existing_partition(int warn, unsigned max)
1570 for (i = 0; i < max; i++) {
1571 struct pte *pe = &ptes[i];
1572 struct partition *p = pe->part_table;
1574 if (p && !is_cleared_partition(p)) {
1581 printf("Selected partition %u\n", pno+1);
1584 printf("No partition is defined yet!\n");
1588 return get_partition(warn, max);
1592 get_nonexisting_partition(int warn, unsigned max)
1597 for (i = 0; i < max; i++) {
1598 struct pte *pe = &ptes[i];
1599 struct partition *p = pe->part_table;
1601 if (p && is_cleared_partition(p)) {
1608 printf("Selected partition %u\n", pno+1);
1611 printf("All primary partitions have been defined already!\n");
1615 return get_partition(warn, max);
1622 display_in_cyl_units = !display_in_cyl_units;
1624 printf("Changing display/entry units to %s\n",
1629 toggle_active(int i)
1631 struct pte *pe = &ptes[i];
1632 struct partition *p = pe->part_table;
1634 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1635 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1636 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1641 toggle_dos_compatibility_flag(void)
1643 dos_compatible_flag = 1 - dos_compatible_flag;
1644 if (dos_compatible_flag) {
1645 sector_offset = g_sectors;
1646 printf("DOS Compatibility flag is set\n");
1649 printf("DOS Compatibility flag is not set\n");
1654 delete_partition(int i)
1656 struct pte *pe = &ptes[i];
1657 struct partition *p = pe->part_table;
1658 struct partition *q = pe->ext_pointer;
1660 /* Note that for the fifth partition (i == 4) we don't actually
1661 * decrement partitions.
1664 if (warn_geometry())
1665 return; /* C/H/S not set */
1669 sun_delete_partition(i);
1673 sgi_delete_partition(i);
1678 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1680 ptes[ext_index].ext_pointer = NULL;
1681 extended_offset = 0;
1687 if (!q->sys_ind && i > 4) {
1688 /* the last one in the chain - just delete */
1691 clear_partition(ptes[i].ext_pointer);
1692 ptes[i].changed = 1;
1694 /* not the last one - further ones will be moved down */
1696 /* delete this link in the chain */
1697 p = ptes[i-1].ext_pointer;
1699 set_start_sect(p, get_start_sect(q));
1700 set_nr_sects(p, get_nr_sects(q));
1701 ptes[i-1].changed = 1;
1702 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1703 /* the first logical in a longer chain */
1706 if (pe->part_table) /* prevent SEGFAULT */
1707 set_start_sect(pe->part_table,
1708 get_partition_start(pe) -
1710 pe->offset = extended_offset;
1714 if (g_partitions > 5) {
1716 while (i < g_partitions) {
1717 ptes[i] = ptes[i+1];
1721 /* the only logical: clear only */
1722 clear_partition(ptes[i].part_table);
1729 int i, sys, origsys;
1730 struct partition *p;
1732 /* If sgi_label then don't use get_existing_partition,
1733 let the user select a partition, since get_existing_partition()
1734 only works for Linux like partition tables. */
1735 if (!LABEL_IS_SGI) {
1736 i = get_existing_partition(0, g_partitions);
1738 i = get_partition(0, g_partitions);
1742 p = ptes[i].part_table;
1743 origsys = sys = get_sysid(i);
1745 /* if changing types T to 0 is allowed, then
1746 the reverse change must be allowed, too */
1747 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1748 printf("Partition %u does not exist yet!\n", i + 1);
1752 sys = read_hex(get_sys_types());
1754 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1755 printf("Type 0 means free space to many systems\n"
1756 "(but not to Linux). Having partitions of\n"
1757 "type 0 is probably unwise.\n");
1761 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1762 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1763 printf("You cannot change a partition into"
1764 " an extended one or vice versa\n");
1770 #if ENABLE_FEATURE_SUN_LABEL
1771 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1772 printf("Consider leaving partition 3 "
1773 "as Whole disk (5),\n"
1774 "as SunOS/Solaris expects it and "
1775 "even Linux likes it\n\n");
1777 #if ENABLE_FEATURE_SGI_LABEL
1780 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1781 (i == 8 && sys != 0)
1784 printf("Consider leaving partition 9 "
1785 "as volume header (0),\nand "
1786 "partition 11 as entire volume (6)"
1787 "as IRIX expects it\n\n");
1793 sun_change_sysid(i, sys);
1794 } else if (LABEL_IS_SGI) {
1795 sgi_change_sysid(i, sys);
1799 printf("Changed system type of partition %u "
1800 "to %x (%s)\n", i + 1, sys,
1801 partition_type(sys));
1802 ptes[i].changed = 1;
1803 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1809 #endif /* FEATURE_FDISK_WRITABLE */
1812 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1813 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1814 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1815 * Lubkin Oct. 1991). */
1818 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1820 int spc = g_heads * g_sectors;
1824 *h = ls / g_sectors;
1825 *s = ls % g_sectors + 1; /* sectors count from 1 */
1829 check_consistency(const struct partition *p, int partition)
1831 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1832 unsigned pec, peh, pes; /* physical ending c, h, s */
1833 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1834 unsigned lec, leh, les; /* logical ending c, h, s */
1836 if (!g_heads || !g_sectors || (partition >= 4))
1837 return; /* do not check extended partitions */
1839 /* physical beginning c, h, s */
1840 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1842 pbs = p->sector & 0x3f;
1844 /* physical ending c, h, s */
1845 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1847 pes = p->end_sector & 0x3f;
1849 /* compute logical beginning (c, h, s) */
1850 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1852 /* compute logical ending (c, h, s) */
1853 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1855 /* Same physical / logical beginning? */
1856 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1857 printf("Partition %u has different physical/logical "
1858 "beginnings (non-Linux?):\n", partition + 1);
1859 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
1860 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
1863 /* Same physical / logical ending? */
1864 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1865 printf("Partition %u has different physical/logical "
1866 "endings:\n", partition + 1);
1867 printf(" phys=(%u, %u, %u) ", pec, peh, pes);
1868 printf("logical=(%u, %u, %u)\n", lec, leh, les);
1871 /* Ending on cylinder boundary? */
1872 if (peh != (g_heads - 1) || pes != g_sectors) {
1873 printf("Partition %u does not end on cylinder boundary\n",
1879 list_disk_geometry(void)
1881 ullong bytes = ((ullong)total_number_of_sectors << 9);
1882 long megabytes = bytes / 1000000;
1884 if (megabytes < 10000)
1885 printf("\nDisk %s: %lu MB, %llu bytes\n",
1886 disk_device, megabytes, bytes);
1888 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1889 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1890 printf("%u heads, %u sectors/track, %u cylinders",
1891 g_heads, g_sectors, g_cylinders);
1892 if (units_per_sector == 1)
1893 printf(", total %"SECT_FMT"u sectors",
1894 total_number_of_sectors / (sector_size/512));
1895 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1897 units_per_sector, sector_size, units_per_sector * sector_size);
1901 * Check whether partition entries are ordered by their starting positions.
1902 * Return 0 if OK. Return i if partition i should have been earlier.
1903 * Two separate checks: primary and logical partitions.
1906 wrong_p_order(int *prev)
1908 const struct pte *pe;
1909 const struct partition *p;
1910 sector_t last_p_start_pos = 0, p_start_pos;
1911 unsigned i, last_i = 0;
1913 for (i = 0; i < g_partitions; i++) {
1916 last_p_start_pos = 0;
1921 p_start_pos = get_partition_start(pe);
1923 if (last_p_start_pos > p_start_pos) {
1929 last_p_start_pos = p_start_pos;
1936 #if ENABLE_FEATURE_FDISK_ADVANCED
1938 * Fix the chain of logicals.
1939 * extended_offset is unchanged, the set of sectors used is unchanged
1940 * The chain is sorted so that sectors increase, and so that
1941 * starting sectors increase.
1943 * After this it may still be that cfdisk doesnt like the table.
1944 * (This is because cfdisk considers expanded parts, from link to
1945 * end of partition, and these may still overlap.)
1947 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1951 fix_chain_of_logicals(void)
1953 int j, oj, ojj, sj, sjj;
1954 struct partition *pj,*pjj,tmp;
1956 /* Stage 1: sort sectors but leave sector of part 4 */
1957 /* (Its sector is the global extended_offset.) */
1959 for (j = 5; j < g_partitions - 1; j++) {
1960 oj = ptes[j].offset;
1961 ojj = ptes[j+1].offset;
1963 ptes[j].offset = ojj;
1964 ptes[j+1].offset = oj;
1965 pj = ptes[j].part_table;
1966 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1967 pjj = ptes[j+1].part_table;
1968 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1969 set_start_sect(ptes[j-1].ext_pointer,
1970 ojj-extended_offset);
1971 set_start_sect(ptes[j].ext_pointer,
1972 oj-extended_offset);
1977 /* Stage 2: sort starting sectors */
1979 for (j = 4; j < g_partitions - 1; j++) {
1980 pj = ptes[j].part_table;
1981 pjj = ptes[j+1].part_table;
1982 sj = get_start_sect(pj);
1983 sjj = get_start_sect(pjj);
1984 oj = ptes[j].offset;
1985 ojj = ptes[j+1].offset;
1986 if (oj+sj > ojj+sjj) {
1990 set_start_sect(pj, ojj+sjj-oj);
1991 set_start_sect(pjj, oj+sj-ojj);
1996 /* Probably something was changed */
1997 for (j = 4; j < g_partitions; j++)
1998 ptes[j].changed = 1;
2003 fix_partition_table_order(void)
2005 struct pte *pei, *pek;
2008 if (!wrong_p_order(NULL)) {
2009 printf("Ordering is already correct\n\n");
2013 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2014 /* partition i should have come earlier, move it */
2015 /* We have to move data in the MBR */
2016 struct partition *pi, *pk, *pe, pbuf;
2020 pe = pei->ext_pointer;
2021 pei->ext_pointer = pek->ext_pointer;
2022 pek->ext_pointer = pe;
2024 pi = pei->part_table;
2025 pk = pek->part_table;
2027 memmove(&pbuf, pi, sizeof(struct partition));
2028 memmove(pi, pk, sizeof(struct partition));
2029 memmove(pk, &pbuf, sizeof(struct partition));
2031 pei->changed = pek->changed = 1;
2035 fix_chain_of_logicals();
2043 list_table(int xtra)
2045 const struct partition *p;
2049 sun_list_table(xtra);
2053 sgi_list_table(xtra);
2057 list_disk_geometry();
2060 xbsd_print_disklabel(xtra);
2064 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2065 but if the device name ends in a digit, say /dev/foo1,
2066 then the partition is called /dev/foo1p3. */
2067 w = strlen(disk_device);
2068 if (w && isdigit(disk_device[w-1]))
2073 // 1 12345678901 12345678901 12345678901 12
2074 printf("%*s Boot Start End Blocks Id System\n",
2077 for (i = 0; i < g_partitions; i++) {
2078 const struct pte *pe = &ptes[i];
2084 if (!p || is_cleared_partition(p))
2087 psects = get_nr_sects(p);
2091 if (sector_size < 1024) {
2092 pblocks /= (1024 / sector_size);
2093 podd = psects % (1024 / sector_size);
2095 if (sector_size > 1024)
2096 pblocks *= (sector_size / 1024);
2098 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
2099 partname(disk_device, i+1, w+2),
2100 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2102 cround(get_partition_start(pe)), /* start */
2103 cround(get_partition_start(pe) + psects /* end */
2104 - (psects ? 1 : 0)),
2105 pblocks, podd ? '+' : ' ', /* odd flag on end */
2106 p->sys_ind, /* type id */
2107 partition_type(p->sys_ind)); /* type name */
2109 check_consistency(p, i);
2112 /* Is partition table in disk order? It need not be, but... */
2113 /* partition table entries are not checked for correct order
2114 * if this is a sgi, sun or aix labeled disk... */
2115 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2117 printf("\nPartition table entries are not in disk order\n");
2121 #if ENABLE_FEATURE_FDISK_ADVANCED
2123 x_list_table(int extend)
2125 const struct pte *pe;
2126 const struct partition *p;
2129 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2130 disk_device, g_heads, g_sectors, g_cylinders);
2131 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2132 for (i = 0; i < g_partitions; i++) {
2134 p = (extend ? pe->ext_pointer : pe->part_table);
2136 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2137 i + 1, p->boot_ind, p->head,
2139 cylinder(p->sector, p->cyl), p->end_head,
2140 sector(p->end_sector),
2141 cylinder(p->end_sector, p->end_cyl),
2142 get_start_sect(p), get_nr_sects(p),
2145 check_consistency(p, i);
2151 #if ENABLE_FEATURE_FDISK_WRITABLE
2153 fill_bounds(sector_t *first, sector_t *last)
2156 const struct pte *pe = &ptes[0];
2157 const struct partition *p;
2159 for (i = 0; i < g_partitions; pe++,i++) {
2161 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2162 first[i] = 0xffffffff;
2165 first[i] = get_partition_start(pe);
2166 last[i] = first[i] + get_nr_sects(p) - 1;
2172 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2174 sector_t total, real_s, real_c;
2176 real_s = sector(s) - 1;
2177 real_c = cylinder(s, c);
2178 total = (real_c * g_sectors + real_s) * g_heads + h;
2180 printf("Partition %u contains sector 0\n", n);
2182 printf("Partition %u: head %u greater than maximum %u\n",
2184 if (real_s >= g_sectors)
2185 printf("Partition %u: sector %u greater than "
2186 "maximum %u\n", n, s, g_sectors);
2187 if (real_c >= g_cylinders)
2188 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2189 "maximum %u\n", n, real_c + 1, g_cylinders);
2190 if (g_cylinders <= 1024 && start != total)
2191 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2192 "total %"SECT_FMT"u\n", n, start, total);
2200 sector_t first[g_partitions], last[g_partitions];
2201 struct partition *p;
2203 if (warn_geometry())
2215 fill_bounds(first, last);
2216 for (i = 0; i < g_partitions; i++) {
2217 struct pte *pe = &ptes[i];
2220 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2221 check_consistency(p, i);
2222 if (get_partition_start(pe) < first[i])
2223 printf("Warning: bad start-of-data in "
2224 "partition %u\n", i + 1);
2225 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2227 total += last[i] + 1 - first[i];
2228 for (j = 0; j < i; j++) {
2229 if ((first[i] >= first[j] && first[i] <= last[j])
2230 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2231 printf("Warning: partition %u overlaps "
2232 "partition %u\n", j + 1, i + 1);
2233 total += first[i] >= first[j] ?
2234 first[i] : first[j];
2235 total -= last[i] <= last[j] ?
2242 if (extended_offset) {
2243 struct pte *pex = &ptes[ext_index];
2244 sector_t e_last = get_start_sect(pex->part_table) +
2245 get_nr_sects(pex->part_table) - 1;
2247 for (i = 4; i < g_partitions; i++) {
2249 p = ptes[i].part_table;
2251 if (i != 4 || i + 1 < g_partitions)
2252 printf("Warning: partition %u "
2253 "is empty\n", i + 1);
2254 } else if (first[i] < extended_offset || last[i] > e_last) {
2255 printf("Logical partition %u not entirely in "
2256 "partition %u\n", i + 1, ext_index + 1);
2261 if (total > g_heads * g_sectors * g_cylinders)
2262 printf("Total allocated sectors %u greater than the maximum "
2263 "%u\n", total, g_heads * g_sectors * g_cylinders);
2265 total = g_heads * g_sectors * g_cylinders - total;
2267 printf("%"SECT_FMT"u unallocated sectors\n", total);
2272 add_partition(int n, int sys)
2274 char mesg[256]; /* 48 does not suffice in Japanese */
2275 int i, num_read = 0;
2276 struct partition *p = ptes[n].part_table;
2277 struct partition *q = ptes[ext_index].part_table;
2278 sector_t limit, temp;
2279 sector_t start, stop = 0;
2280 sector_t first[g_partitions], last[g_partitions];
2282 if (p && p->sys_ind) {
2283 printf(msg_part_already_defined, n + 1);
2286 fill_bounds(first, last);
2288 start = sector_offset;
2289 if (display_in_cyl_units || !total_number_of_sectors)
2290 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2292 limit = total_number_of_sectors - 1;
2293 if (extended_offset) {
2294 first[ext_index] = extended_offset;
2295 last[ext_index] = get_start_sect(q) +
2296 get_nr_sects(q) - 1;
2299 start = extended_offset + sector_offset;
2300 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2302 if (display_in_cyl_units)
2303 for (i = 0; i < g_partitions; i++)
2304 first[i] = (cround(first[i]) - 1) * units_per_sector;
2306 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2309 for (i = 0; i < g_partitions; i++) {
2312 if (start == ptes[i].offset)
2313 start += sector_offset;
2314 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2315 if (start >= first[i] && start <= lastplusoff)
2316 start = lastplusoff + 1;
2320 if (start >= temp+units_per_sector && num_read) {
2321 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2325 if (!num_read && start == temp) {
2326 sector_t saved_start;
2328 saved_start = start;
2329 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2331 if (display_in_cyl_units) {
2332 start = (start - 1) * units_per_sector;
2333 if (start < saved_start)
2334 start = saved_start;
2338 } while (start != temp || !num_read);
2339 if (n > 4) { /* NOT for fifth partition */
2340 struct pte *pe = &ptes[n];
2342 pe->offset = start - sector_offset;
2343 if (pe->offset == extended_offset) { /* must be corrected */
2345 if (sector_offset == 1)
2350 for (i = 0; i < g_partitions; i++) {
2351 struct pte *pe = &ptes[i];
2353 if (start < pe->offset && limit >= pe->offset)
2354 limit = pe->offset - 1;
2355 if (start < first[i] && limit >= first[i])
2356 limit = first[i] - 1;
2358 if (start > limit) {
2359 printf("No free sectors available\n");
2364 if (cround(start) == cround(limit)) {
2367 snprintf(mesg, sizeof(mesg),
2368 "Last %s or +size or +sizeM or +sizeK",
2369 str_units(SINGULAR));
2370 stop = read_int(cround(start), cround(limit), cround(limit),
2371 cround(start), mesg);
2372 if (display_in_cyl_units) {
2373 stop = stop * units_per_sector - 1;
2379 set_partition(n, 0, start, stop, sys);
2381 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2383 if (IS_EXTENDED(sys)) {
2384 struct pte *pe4 = &ptes[4];
2385 struct pte *pen = &ptes[n];
2388 pen->ext_pointer = p;
2389 pe4->offset = extended_offset = start;
2390 pe4->sectorbuffer = xzalloc(sector_size);
2391 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2392 pe4->ext_pointer = pe4->part_table + 1;
2401 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2402 struct pte *pe = &ptes[g_partitions];
2404 pe->sectorbuffer = xzalloc(sector_size);
2405 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2406 pe->ext_pointer = pe->part_table + 1;
2411 add_partition(g_partitions - 1, LINUX_NATIVE);
2417 int i, free_primary = 0;
2419 if (warn_geometry())
2423 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2427 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2431 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2432 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2433 "table first (use 'o'). This will destroy the present disk contents.\n");
2437 for (i = 0; i < 4; i++)
2438 free_primary += !ptes[i].part_table->sys_ind;
2440 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2441 printf("The maximum number of partitions has been created\n");
2445 if (!free_primary) {
2446 if (extended_offset)
2449 printf("You must delete some partition and add "
2450 "an extended partition first\n");
2453 snprintf(line, sizeof(line),
2456 " p primary partition (1-4)\n",
2458 "l logical (5 or over)" : "e extended"));
2460 c = read_nonempty(line);
2461 if (c == 'p' || c == 'P') {
2462 i = get_nonexisting_partition(0, 4);
2464 add_partition(i, LINUX_NATIVE);
2467 if (c == 'l' && extended_offset) {
2471 if (c == 'e' && !extended_offset) {
2472 i = get_nonexisting_partition(0, 4);
2474 add_partition(i, EXTENDED);
2477 printf("Invalid partition number "
2478 "for type '%c'\n", c);
2489 for (i = 0; i < 3; i++)
2490 if (ptes[i].changed)
2491 ptes[3].changed = 1;
2492 for (i = 3; i < g_partitions; i++) {
2493 struct pte *pe = &ptes[i];
2496 write_part_table_flag(pe->sectorbuffer);
2497 write_sector(pe->offset, pe->sectorbuffer);
2501 else if (LABEL_IS_SGI) {
2502 /* no test on change? the printf below might be mistaken */
2505 else if (LABEL_IS_SUN) {
2508 for (i = 0; i < 8; i++)
2509 if (ptes[i].changed)
2515 printf("The partition table has been altered!\n\n");
2516 reread_partition_table(1);
2520 reread_partition_table(int leave)
2524 printf("Calling ioctl() to re-read partition table\n");
2526 /* sleep(2); Huh? */
2527 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2528 "WARNING: rereading partition table "
2529 "failed, kernel still uses old table");
2533 "\nWARNING: If you have created or modified any DOS 6.x\n"
2534 "partitions, please see the fdisk manual page for additional\n"
2539 if (ENABLE_FEATURE_CLEAN_UP)
2544 #endif /* FEATURE_FDISK_WRITABLE */
2546 #if ENABLE_FEATURE_FDISK_ADVANCED
2547 #define MAX_PER_LINE 16
2549 print_buffer(char *pbuffer)
2553 for (i = 0, l = 0; i < sector_size; i++, l++) {
2555 printf("0x%03X:", i);
2556 printf(" %02X", (unsigned char) pbuffer[i]);
2557 if (l == MAX_PER_LINE - 1) {
2572 printf("Device: %s\n", disk_device);
2573 if (LABEL_IS_SGI || LABEL_IS_SUN)
2574 print_buffer(MBRbuffer);
2576 for (i = 3; i < g_partitions; i++)
2577 print_buffer(ptes[i].sectorbuffer);
2582 move_begin(unsigned i)
2584 struct pte *pe = &ptes[i];
2585 struct partition *p = pe->part_table;
2586 sector_t new, first;
2588 if (warn_geometry())
2590 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2591 printf("Partition %u has no data area\n", i + 1);
2594 first = get_partition_start(pe);
2595 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2596 "New beginning of data") - pe->offset;
2598 if (new != get_nr_sects(p)) {
2599 first = get_nr_sects(p) + get_start_sect(p) - new;
2600 set_nr_sects(p, first);
2601 set_start_sect(p, new);
2613 c = tolower(read_nonempty("Expert command (m for help): "));
2621 move_begin(get_partition(0, g_partitions));
2624 user_cylinders = g_cylinders =
2625 read_int(1, g_cylinders, 1048576, 0,
2626 "Number of cylinders");
2628 sun_set_ncyl(g_cylinders);
2638 else if (LABEL_IS_SUN)
2640 else if (LABEL_IS_DOS)
2645 fix_partition_table_order();
2648 #if ENABLE_FEATURE_SGI_LABEL
2653 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2672 if (ENABLE_FEATURE_CLEAN_UP)
2679 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2680 "Number of sectors");
2681 if (dos_compatible_flag) {
2682 sector_offset = g_sectors;
2683 printf("Warning: setting sector offset for DOS "
2692 write_table(); /* does not return */
2696 sun_set_pcylcount();
2703 #endif /* ADVANCED mode */
2706 is_ide_cdrom_or_tape(const char *device)
2710 struct stat statbuf;
2713 /* No device was given explicitly, and we are trying some
2714 likely things. But opening /dev/hdc may produce errors like
2715 "hdc: tray open or drive not ready"
2716 if it happens to be a CD-ROM drive. It even happens that
2717 the process hangs on the attempt to read a music CD.
2718 So try to be careful. This only works since 2.1.73. */
2720 if (strncmp("/dev/hd", device, 7))
2723 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2724 procf = fopen_for_read(buf);
2725 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2726 is_ide = (!strncmp(buf, "cdrom", 5) ||
2727 !strncmp(buf, "tape", 4));
2729 /* Now when this proc file does not exist, skip the
2730 device when it is read-only. */
2731 if (stat(device, &statbuf) == 0)
2732 is_ide = ((statbuf.st_mode & 0222) == 0);
2741 open_list_and_close(const char *device, int user_specified)
2745 disk_device = device;
2746 if (setjmp(listingbuf))
2748 if (!user_specified)
2749 if (is_ide_cdrom_or_tape(device))
2752 /* Open disk_device, save file descriptor to dev_fd */
2754 gb = get_boot(TRY_ONLY);
2755 if (gb > 0) { /* I/O error */
2756 /* Ignore other errors, since we try IDE
2757 and SCSI hard disks which may not be
2758 installed on the system. */
2759 if (user_specified || errno == EACCES)
2760 bb_perror_msg("can't open '%s'", device);
2764 if (gb < 0) { /* no DOS signature */
2765 list_disk_geometry();
2768 #if ENABLE_FEATURE_OSF_LABEL
2769 if (bsd_trydev(device) < 0)
2771 printf("Disk %s doesn't contain a valid "
2772 "partition table\n", device);
2775 #if ENABLE_FEATURE_FDISK_WRITABLE
2776 if (!LABEL_IS_SUN && g_partitions > 4) {
2777 delete_partition(ext_index);
2785 /* for fdisk -l: try all things in /proc/partitions
2786 that look like a partition name (do not end in a digit) */
2788 list_devs_in_proc_partititons(void)
2791 char line[100], ptname[100], devname[120], *s;
2794 procpt = fopen_or_warn("/proc/partitions", "r");
2796 while (fgets(line, sizeof(line), procpt)) {
2797 if (sscanf(line, " %u %u %u %[^\n ]",
2798 &ma, &mi, &sz, ptname) != 4)
2800 for (s = ptname; *s; s++)
2804 sprintf(devname, "/dev/%s", ptname);
2805 open_list_and_close(devname, 0);
2807 #if ENABLE_FEATURE_CLEAN_UP
2812 #if ENABLE_FEATURE_FDISK_WRITABLE
2814 unknown_command(int c)
2816 printf("%c: unknown command\n", c);
2820 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2821 int fdisk_main(int argc, char **argv)
2826 * fdisk -l [-b sectorsize] [-u] device ...
2827 * fdisk -s [partition] ...
2828 * fdisk [-b sectorsize] [-u] device
2830 * Options -C, -H, -S set the geometry.
2834 close_dev_fd(); /* needed: fd 3 must not stay closed */
2836 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2837 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2838 §or_size, &user_cylinders, &user_heads, &user_sectors);
2841 if (opt & OPT_b) { // -b
2842 /* Ugly: this sector size is really per device,
2843 so cannot be combined with multiple disks,
2844 and the same goes for the C/H/S options.
2846 if (sector_size != 512 && sector_size != 1024
2847 && sector_size != 2048)
2850 user_set_sector_size = 1;
2852 if (user_heads <= 0 || user_heads >= 256)
2854 if (user_sectors <= 0 || user_sectors >= 64)
2857 display_in_cyl_units = 0; // -u
2859 #if ENABLE_FEATURE_FDISK_WRITABLE
2866 open_list_and_close(*argv, 1);
2869 /* we don't have device names, */
2870 /* use /proc/partitions instead */
2871 list_devs_in_proc_partititons();
2874 #if ENABLE_FEATURE_FDISK_WRITABLE
2878 #if ENABLE_FEATURE_FDISK_BLKSIZE
2885 for (j = 0; j < argc; j++) {
2886 unsigned long long size;
2887 fd = xopen(argv[j], O_RDONLY);
2888 size = bb_BLKGETSIZE_sectors(fd) / 2;
2891 printf("%llu\n", size);
2893 printf("%s: %llu\n", argv[j], size);
2899 #if ENABLE_FEATURE_FDISK_WRITABLE
2903 disk_device = argv[0];
2904 get_boot(OPEN_MAIN);
2907 /* OSF label, and no DOS label */
2908 printf("Detected an OSF/1 disklabel on %s, entering "
2909 "disklabel mode\n", disk_device);
2911 /*Why do we do this? It seems to be counter-intuitive*/
2912 current_label_type = LABEL_DOS;
2913 /* If we return we may want to make an empty DOS label? */
2919 c = tolower(read_nonempty("Command (m for help): "));
2923 toggle_active(get_partition(1, g_partitions));
2924 else if (LABEL_IS_SUN)
2925 toggle_sunflags(get_partition(1, g_partitions),
2927 else if (LABEL_IS_SGI)
2928 sgi_set_bootpartition(
2929 get_partition(1, g_partitions));
2935 printf("\nThe current boot file is: %s\n",
2936 sgi_get_bootfile());
2937 if (read_maybe_empty("Please enter the name of the "
2938 "new boot file: ") == '\n')
2939 printf("Boot file unchanged\n");
2941 sgi_set_bootfile(line_ptr);
2943 #if ENABLE_FEATURE_OSF_LABEL
2950 toggle_dos_compatibility_flag();
2951 else if (LABEL_IS_SUN)
2952 toggle_sunflags(get_partition(1, g_partitions),
2954 else if (LABEL_IS_SGI)
2955 sgi_set_swappartition(
2956 get_partition(1, g_partitions));
2963 /* If sgi_label then don't use get_existing_partition,
2964 let the user select a partition, since
2965 get_existing_partition() only works for Linux-like
2967 if (!LABEL_IS_SGI) {
2968 j = get_existing_partition(1, g_partitions);
2970 j = get_partition(1, g_partitions);
2973 delete_partition(j);
2982 list_types(get_sys_types());
2997 if (ENABLE_FEATURE_CLEAN_UP)
3002 #if ENABLE_FEATURE_SUN_LABEL
3016 write_table(); /* does not return */
3018 #if ENABLE_FEATURE_FDISK_ADVANCED
3021 printf("\n\tSorry, no experts menu for SGI "
3022 "partition tables available\n\n");
3033 #endif /* FEATURE_FDISK_WRITABLE */