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 #include <assert.h> /* assert */
14 /* Looks like someone forgot to add this to config system */
15 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
16 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
17 # define USE_FEATURE_FDISK_BLKSIZE(a)
20 #define DEFAULT_SECTOR_SIZE 512
21 #define MAX_SECTOR_SIZE 2048
22 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
23 #define MAXIMUM_PARTS 60
25 #define ACTIVE_FLAG 0x80
28 #define WIN98_EXTENDED 0x0f
29 #define LINUX_PARTITION 0x81
30 #define LINUX_SWAP 0x82
31 #define LINUX_NATIVE 0x83
32 #define LINUX_EXTENDED 0x85
33 #define LINUX_LVM 0x8e
34 #define LINUX_RAID 0xfd
36 #define IS_EXTENDED(i) \
37 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
39 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
41 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
42 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
46 unsigned char sectors;
47 unsigned short cylinders;
51 #define HDIO_GETGEO 0x0301 /* get device geometry */
57 static unsigned sector_size = DEFAULT_SECTOR_SIZE;
58 static unsigned user_set_sector_size;
59 static unsigned sector_offset = 1;
61 #if ENABLE_FEATURE_OSF_LABEL
62 static int possibly_osf_label;
65 static unsigned heads, sectors, cylinders;
66 static void update_units(void);
70 * return partition name - uses static storage unless buf is supplied
73 partname(const char *dev, int pno, int lth)
75 static char buffer[80];
82 bufsiz = sizeof(buffer);
87 if (isdigit(dev[w-1]))
90 /* devfs kludge - note: fdisk partition names are not supposed
91 to equal kernel names, so there is no reason to do this */
92 if (strcmp(dev + w - 4, "disc") == 0) {
100 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
101 lth-wp-2, w, dev, p, pno);
103 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
109 unsigned char boot_ind; /* 0x80 - active */
110 unsigned char head; /* starting head */
111 unsigned char sector; /* starting sector */
112 unsigned char cyl; /* starting cylinder */
113 unsigned char sys_ind; /* What partition type */
114 unsigned char end_head; /* end head */
115 unsigned char end_sector; /* end sector */
116 unsigned char end_cyl; /* end cylinder */
117 unsigned char start4[4]; /* starting sector counting from 0 */
118 unsigned char size4[4]; /* nr of sectors in partition */
122 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
127 label_dos, label_sun, label_sgi, label_aix, label_osf
129 #define LABEL_IS_DOS (label_dos == current_label_type)
131 #if ENABLE_FEATURE_SUN_LABEL
132 #define LABEL_IS_SUN (label_sun == current_label_type)
133 #define STATIC_SUN static
135 #define LABEL_IS_SUN 0
136 #define STATIC_SUN extern
139 #if ENABLE_FEATURE_SGI_LABEL
140 #define LABEL_IS_SGI (label_sgi == current_label_type)
141 #define STATIC_SGI static
143 #define LABEL_IS_SGI 0
144 #define STATIC_SGI extern
147 #if ENABLE_FEATURE_AIX_LABEL
148 #define LABEL_IS_AIX (label_aix == current_label_type)
149 #define STATIC_AIX static
151 #define LABEL_IS_AIX 0
152 #define STATIC_AIX extern
155 #if ENABLE_FEATURE_OSF_LABEL
156 #define LABEL_IS_OSF (label_osf == current_label_type)
157 #define STATIC_OSF static
159 #define LABEL_IS_OSF 0
160 #define STATIC_OSF extern
163 enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
165 static enum label_type current_label_type;
167 static const char *disk_device;
168 static int fd; /* the disk */
169 static int partitions = 4; /* maximum partition + 1 */
170 static int display_in_cyl_units = 1;
171 static unsigned units_per_sector = 1;
172 #if ENABLE_FEATURE_FDISK_WRITABLE
173 static void change_units(void);
174 static void reread_partition_table(int leave);
175 static void delete_partition(int i);
176 static int get_partition(int warn, int max);
177 static void list_types(const struct systypes *sys);
178 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
180 static const char *partition_type(unsigned char type);
181 static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
182 static void get_geometry(void);
183 static int get_boot(enum action what);
188 #define hex_val(c) ({ \
190 isdigit(_c) ? _c - '0' : \
191 tolower(_c) + 10 - 'a'; \
194 #define LINE_LENGTH 80
195 #define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
196 (n) * sizeof(struct partition)))
197 #define sector(s) ((s) & 0x3f)
198 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
200 #define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
201 ((h) + heads * cylinder(s,c)))
202 #define set_hsc(h,s,c,sector) \
204 s = sector % sectors + 1; \
206 h = sector % heads; \
209 s |= (sector >> 2) & 0xc0; \
212 static unsigned get_start_sect(const struct partition *p);
213 static unsigned get_nr_sects(const struct partition *p);
216 * per partition table entry data
218 * The four primary partitions have the same sectorbuffer (MBRbuffer)
219 * and have NULL ext_pointer.
220 * Each logical partition table entry has two pointers, one for the
221 * partition and one link to the next one.
224 struct partition *part_table; /* points into sectorbuffer */
225 struct partition *ext_pointer; /* points into sectorbuffer */
226 #if ENABLE_FEATURE_FDISK_WRITABLE
227 char changed; /* boolean */
229 off_t offset; /* disk sector number */
230 char *sectorbuffer; /* disk sector contents */
234 /* Raw disk label. For DOS-type partition tables the MBR,
235 * with descriptions of the primary partitions. */
236 char MBRbuffer[MAX_SECTOR_SIZE];
237 /* Partition tables */
238 struct pte ptes[MAXIMUM_PARTS];
241 #define G (*(struct globals*)bb_common_bufsiz1)
242 #define MBRbuffer (G.MBRbuffer)
243 #define ptes (G.ptes)
245 #if ENABLE_FEATURE_FDISK_WRITABLE
247 set_all_unchanged(void)
251 for (i = 0; i < MAXIMUM_PARTS; i++)
255 static ATTRIBUTE_ALWAYS_INLINE void
260 #endif /* FEATURE_FDISK_WRITABLE */
262 static ATTRIBUTE_ALWAYS_INLINE struct partition *
263 get_part_table(int i)
265 return ptes[i].part_table;
270 { /* n==1: use singular */
272 return display_in_cyl_units ? _("cylinder") : _("sector");
274 return display_in_cyl_units ? _("cylinders") : _("sectors");
278 valid_part_table_flag(const char *mbuffer)
280 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
283 #if ENABLE_FEATURE_FDISK_WRITABLE
284 static ATTRIBUTE_ALWAYS_INLINE void
285 write_part_table_flag(char *b)
291 static char line_buffer[LINE_LENGTH];
292 static char *line_ptr;
294 /* read line; return 0 or first printable char */
296 read_line(const char *prompt)
300 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
302 exit(0); /* Ctrl-D or Ctrl-C */
304 if (line_buffer[sz-1] == '\n')
305 line_buffer[--sz] = '\0';
307 line_ptr = line_buffer;
308 while (*line_ptr && !isgraph(*line_ptr))
314 read_nonempty(const char *mesg)
316 while (!read_line(mesg)) /* repeat */;
321 read_maybe_empty(const char *mesg)
323 if (!read_line(mesg)) {
324 line_ptr = line_buffer;
332 read_hex(const struct systypes *sys)
336 read_nonempty(_("Hex code (type L to list codes): "));
337 if (*line_ptr == 'l' || *line_ptr == 'L') {
341 v = bb_strtoul(line_ptr, NULL, 16);
343 /* Bad input also triggers this */
348 #endif /* FEATURE_FDISK_WRITABLE */
350 #include "fdisk_aix.c"
353 unsigned char info[128]; /* Informative text string */
354 unsigned char spare0[14];
356 unsigned char spare1;
358 unsigned char spare2;
361 unsigned char spare1[246]; /* Boot information etc. */
362 unsigned short rspeed; /* Disk rotational speed */
363 unsigned short pcylcount; /* Physical cylinder count */
364 unsigned short sparecyl; /* extra sects per cylinder */
365 unsigned char spare2[4]; /* More magic... */
366 unsigned short ilfact; /* Interleave factor */
367 unsigned short ncyl; /* Data cylinder count */
368 unsigned short nacyl; /* Alt. cylinder count */
369 unsigned short ntrks; /* Tracks per cylinder */
370 unsigned short nsect; /* Sectors per track */
371 unsigned char spare3[4]; /* Even more magic... */
372 struct sun_partinfo {
373 uint32_t start_cylinder;
374 uint32_t num_sectors;
376 unsigned short magic; /* Magic number */
377 unsigned short csum; /* Label xor'd checksum */
379 #define sunlabel ((sun_partition *)MBRbuffer)
381 #define SUN_WHOLE_DISK 5
382 STATIC_OSF void bsd_select(void);
383 STATIC_OSF void xbsd_print_disklabel(int);
384 #include "fdisk_osf.c"
386 #define SGI_VOLHDR 0x00
387 /* 1 and 2 were used for drive types no longer supported by SGI */
388 #define SGI_SWAP 0x03
389 /* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
390 #define SGI_VOLUME 0x06
392 #define SGI_LVOL 0x08
393 #define SGI_RLVOL 0x09
395 #define SGI_XFSLOG 0x0b
398 #define SGI_ENTIRE_DISK SGI_VOLUME
399 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
401 fdisk_swap16(uint16_t x)
403 return (x << 8) | (x >> 8);
407 fdisk_swap32(uint32_t x)
410 ((x & 0xFF00) << 8) |
411 ((x & 0xFF0000) >> 8) |
416 STATIC_SGI const struct systypes sgi_sys_types[];
417 STATIC_SGI unsigned sgi_get_num_sectors(int i);
418 STATIC_SGI int sgi_get_sysid(int i);
419 STATIC_SGI void sgi_delete_partition(int i);
420 STATIC_SGI void sgi_change_sysid(int i, int sys);
421 STATIC_SGI void sgi_list_table(int xtra);
422 #if ENABLE_FEATURE_FDISK_ADVANCED
423 STATIC_SGI void sgi_set_xcyl(void);
425 STATIC_SGI int verify_sgi(int verbose);
426 STATIC_SGI void sgi_add_partition(int n, int sys);
427 STATIC_SGI void sgi_set_swappartition(int i);
428 STATIC_SGI const char *sgi_get_bootfile(void);
429 STATIC_SGI void sgi_set_bootfile(const char* aFile);
430 STATIC_SGI void create_sgiinfo(void);
431 STATIC_SGI void sgi_write_table(void);
432 STATIC_SGI void sgi_set_bootpartition(int i);
433 #include "fdisk_sgi.c"
435 STATIC_SUN const struct systypes sun_sys_types[];
436 STATIC_SUN void sun_delete_partition(int i);
437 STATIC_SUN void sun_change_sysid(int i, int sys);
438 STATIC_SUN void sun_list_table(int xtra);
439 STATIC_SUN void add_sun_partition(int n, int sys);
440 #if ENABLE_FEATURE_FDISK_ADVANCED
441 STATIC_SUN void sun_set_alt_cyl(void);
442 STATIC_SUN void sun_set_ncyl(int cyl);
443 STATIC_SUN void sun_set_xcyl(void);
444 STATIC_SUN void sun_set_ilfact(void);
445 STATIC_SUN void sun_set_rspeed(void);
446 STATIC_SUN void sun_set_pcylcount(void);
448 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
449 STATIC_SUN void verify_sun(void);
450 STATIC_SUN void sun_write_table(void);
451 #include "fdisk_sun.c"
453 /* DOS partition types */
455 static const struct systypes i386_sys_types[] = {
458 { "\x04" "FAT16 <32M" },
459 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
460 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
461 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
462 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
463 { "\x0b" "Win95 FAT32" },
464 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is 'Extended Int 13h' */
465 { "\x0e" "Win95 FAT16 (LBA)" },
466 { "\x0f" "Win95 Ext'd (LBA)" },
467 { "\x11" "Hidden FAT12" },
468 { "\x12" "Compaq diagnostics" },
469 { "\x14" "Hidden FAT16 <32M" },
470 { "\x16" "Hidden FAT16" },
471 { "\x17" "Hidden HPFS/NTFS" },
472 { "\x1b" "Hidden Win95 FAT32" },
473 { "\x1c" "Hidden W95 FAT32 (LBA)" },
474 { "\x1e" "Hidden W95 FAT16 (LBA)" },
475 { "\x3c" "Part.Magic recovery" },
476 { "\x41" "PPC PReP Boot" },
478 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
479 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
480 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
481 { "\x82" "Linux swap" }, /* also Solaris */
483 { "\x84" "OS/2 hidden C: drive" },
484 { "\x85" "Linux extended" },
485 { "\x86" "NTFS volume set" },
486 { "\x87" "NTFS volume set" },
487 { "\x8e" "Linux LVM" },
488 { "\x9f" "BSD/OS" }, /* BSDI */
489 { "\xa0" "Thinkpad hibernation" },
490 { "\xa5" "FreeBSD" }, /* various BSD flavours */
491 { "\xa6" "OpenBSD" },
492 { "\xa8" "Darwin UFS" },
494 { "\xab" "Darwin boot" },
495 { "\xb7" "BSDI fs" },
496 { "\xb8" "BSDI swap" },
497 { "\xbe" "Solaris boot" },
498 { "\xeb" "BeOS fs" },
499 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
500 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
501 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
502 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
503 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
504 autodetect using persistent
506 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
507 { "\x02" "XENIX root" },
508 { "\x03" "XENIX usr" },
509 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
510 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
512 { "\x18" "AST SmartSleep" },
513 { "\x24" "NEC DOS" },
515 { "\x40" "Venix 80286" },
517 { "\x4e" "QNX4.x 2nd part" },
518 { "\x4f" "QNX4.x 3rd part" },
519 { "\x50" "OnTrack DM" },
520 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
521 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
522 { "\x53" "OnTrack DM6 Aux3" },
523 { "\x54" "OnTrackDM6" },
524 { "\x55" "EZ-Drive" },
525 { "\x56" "Golden Bow" },
526 { "\x5c" "Priam Edisk" },
527 { "\x61" "SpeedStor" },
528 { "\x64" "Novell Netware 286" },
529 { "\x65" "Novell Netware 386" },
530 { "\x70" "DiskSecure Multi-Boot" },
533 { "\x94" "Amoeba BBT" }, /* (bad block table) */
534 { "\xa7" "NeXTSTEP" },
535 { "\xbb" "Boot Wizard hidden" },
536 { "\xc1" "DRDOS/sec (FAT-12)" },
537 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
538 { "\xc6" "DRDOS/sec (FAT-16)" },
540 { "\xda" "Non-FS data" },
541 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
542 Concurrent DOS or CTOS */
543 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
544 { "\xdf" "BootIt" }, /* BootIt EMBRM */
545 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
546 extended partition */
547 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
548 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
549 partition < 1024 cyl. */
550 { "\xf1" "SpeedStor" },
551 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
552 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
553 { "\xff" "BBT" }, /* Xenix Bad Block Table */
559 #if ENABLE_FEATURE_FDISK_WRITABLE
560 /* start_sect and nr_sects are stored little endian on all machines */
561 /* moreover, they are not aligned correctly */
563 store4_little_endian(unsigned char *cp, unsigned val)
570 #endif /* FEATURE_FDISK_WRITABLE */
573 read4_little_endian(const unsigned char *cp)
575 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
578 #if ENABLE_FEATURE_FDISK_WRITABLE
580 set_start_sect(struct partition *p, unsigned start_sect)
582 store4_little_endian(p->start4, start_sect);
587 get_start_sect(const struct partition *p)
589 return read4_little_endian(p->start4);
592 #if ENABLE_FEATURE_FDISK_WRITABLE
594 set_nr_sects(struct partition *p, unsigned nr_sects)
596 store4_little_endian(p->size4, nr_sects);
601 get_nr_sects(const struct partition *p)
603 return read4_little_endian(p->size4);
606 /* normally O_RDWR, -l option gives O_RDONLY */
607 static int type_open = O_RDWR;
610 static int ext_index; /* the prime extended partition */
611 static int listing; /* no aborts for fdisk -l */
612 static int dos_compatible_flag = ~0;
613 #if ENABLE_FEATURE_FDISK_WRITABLE
614 static int dos_changed;
615 static int nowarn; /* no warnings for fdisk -l/-s */
620 static unsigned user_cylinders, user_heads, user_sectors;
621 static unsigned pt_heads, pt_sectors;
622 static unsigned kern_heads, kern_sectors;
624 static off_t extended_offset; /* offset of link pointers */
626 static unsigned long long total_number_of_sectors;
629 static jmp_buf listingbuf;
631 static void fdisk_fatal(enum failure why)
637 longjmp(listingbuf, 1);
642 message = "\nUnable to open %s";
645 message = "\nUnable to read %s";
648 message = "\nUnable to seek on %s";
650 case unable_to_write:
651 message = "\nUnable to write %s";
654 message = "\nBLKGETSIZE ioctl failed on %s";
657 message = "\nFatal error";
660 bb_error_msg_and_die(message, disk_device);
664 seek_sector(off_t secno)
666 off_t offset = secno * sector_size;
667 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
668 fdisk_fatal(unable_to_seek);
671 #if ENABLE_FEATURE_FDISK_WRITABLE
673 write_sector(off_t secno, char *buf)
676 if (write(fd, buf, sector_size) != sector_size)
677 fdisk_fatal(unable_to_write);
681 /* Allocate a buffer and read a partition table sector */
683 read_pte(struct pte *pe, off_t offset)
686 pe->sectorbuffer = xmalloc(sector_size);
688 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
689 fdisk_fatal(unable_to_read);
690 #if ENABLE_FEATURE_FDISK_WRITABLE
693 pe->part_table = pe->ext_pointer = NULL;
697 get_partition_start(const struct pte *pe)
699 return pe->offset + get_start_sect(pe->part_table);
702 #if ENABLE_FEATURE_FDISK_WRITABLE
704 * Avoid warning about DOS partitions when no DOS partition was changed.
705 * Here a heuristic "is probably dos partition".
706 * We might also do the opposite and warn in all cases except
707 * for "is probably nondos partition".
710 is_dos_partition(int t)
712 return (t == 1 || t == 4 || t == 6 ||
713 t == 0x0b || t == 0x0c || t == 0x0e ||
714 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
715 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
716 t == 0xc1 || t == 0xc4 || t == 0xc6);
722 puts(_("Command Action"));
724 puts(_("a\ttoggle a read only flag")); /* sun */
725 puts(_("b\tedit bsd disklabel"));
726 puts(_("c\ttoggle the mountable flag")); /* sun */
727 puts(_("d\tdelete a partition"));
728 puts(_("l\tlist known partition types"));
729 puts(_("n\tadd a new partition"));
730 puts(_("o\tcreate a new empty DOS partition table"));
731 puts(_("p\tprint the partition table"));
732 puts(_("q\tquit without saving changes"));
733 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
734 puts(_("t\tchange a partition's system id"));
735 puts(_("u\tchange display/entry units"));
736 puts(_("v\tverify the partition table"));
737 puts(_("w\twrite table to disk and exit"));
738 #if ENABLE_FEATURE_FDISK_ADVANCED
739 puts(_("x\textra functionality (experts only)"));
741 } else if (LABEL_IS_SGI) {
742 puts(_("a\tselect bootable partition")); /* sgi flavour */
743 puts(_("b\tedit bootfile entry")); /* sgi */
744 puts(_("c\tselect sgi swap partition")); /* sgi flavour */
745 puts(_("d\tdelete a partition"));
746 puts(_("l\tlist known partition types"));
747 puts(_("n\tadd a new partition"));
748 puts(_("o\tcreate a new empty DOS partition table"));
749 puts(_("p\tprint the partition table"));
750 puts(_("q\tquit without saving changes"));
751 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
752 puts(_("t\tchange a partition's system id"));
753 puts(_("u\tchange display/entry units"));
754 puts(_("v\tverify the partition table"));
755 puts(_("w\twrite table to disk and exit"));
756 } else if (LABEL_IS_AIX) {
757 puts(_("o\tcreate a new empty DOS partition table"));
758 puts(_("q\tquit without saving changes"));
759 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
761 puts(_("a\ttoggle a bootable flag"));
762 puts(_("b\tedit bsd disklabel"));
763 puts(_("c\ttoggle the dos compatibility flag"));
764 puts(_("d\tdelete a partition"));
765 puts(_("l\tlist known partition types"));
766 puts(_("n\tadd a new partition"));
767 puts(_("o\tcreate a new empty DOS partition table"));
768 puts(_("p\tprint the partition table"));
769 puts(_("q\tquit without saving changes"));
770 puts(_("s\tcreate a new empty Sun disklabel")); /* sun */
771 puts(_("t\tchange a partition's system id"));
772 puts(_("u\tchange display/entry units"));
773 puts(_("v\tverify the partition table"));
774 puts(_("w\twrite table to disk and exit"));
775 #if ENABLE_FEATURE_FDISK_ADVANCED
776 puts(_("x\textra functionality (experts only)"));
780 #endif /* FEATURE_FDISK_WRITABLE */
783 #if ENABLE_FEATURE_FDISK_ADVANCED
787 puts(_("Command Action"));
789 puts(_("a\tchange number of alternate cylinders")); /*sun*/
790 puts(_("c\tchange number of cylinders"));
791 puts(_("d\tprint the raw data in the partition table"));
792 puts(_("e\tchange number of extra sectors per cylinder"));/*sun*/
793 puts(_("h\tchange number of heads"));
794 puts(_("i\tchange interleave factor")); /*sun*/
795 puts(_("o\tchange rotation speed (rpm)")); /*sun*/
796 puts(_("p\tprint the partition table"));
797 puts(_("q\tquit without saving changes"));
798 puts(_("r\treturn to main menu"));
799 puts(_("s\tchange number of sectors/track"));
800 puts(_("v\tverify the partition table"));
801 puts(_("w\twrite table to disk and exit"));
802 puts(_("y\tchange number of physical cylinders")); /*sun*/
803 } else if (LABEL_IS_SGI) {
804 puts(_("b\tmove beginning of data in a partition")); /* !sun */
805 puts(_("c\tchange number of cylinders"));
806 puts(_("d\tprint the raw data in the partition table"));
807 puts(_("e\tlist extended partitions")); /* !sun */
808 puts(_("g\tcreate an IRIX (SGI) partition table"));/* sgi */
809 puts(_("h\tchange number of heads"));
810 puts(_("p\tprint the partition table"));
811 puts(_("q\tquit without saving changes"));
812 puts(_("r\treturn to main menu"));
813 puts(_("s\tchange number of sectors/track"));
814 puts(_("v\tverify the partition table"));
815 puts(_("w\twrite table to disk and exit"));
816 } else if (LABEL_IS_AIX) {
817 puts(_("b\tmove beginning of data in a partition")); /* !sun */
818 puts(_("c\tchange number of cylinders"));
819 puts(_("d\tprint the raw data in the partition table"));
820 puts(_("e\tlist extended partitions")); /* !sun */
821 puts(_("g\tcreate an IRIX (SGI) partition table"));/* sgi */
822 puts(_("h\tchange number of heads"));
823 puts(_("p\tprint the partition table"));
824 puts(_("q\tquit without saving changes"));
825 puts(_("r\treturn to main menu"));
826 puts(_("s\tchange number of sectors/track"));
827 puts(_("v\tverify the partition table"));
828 puts(_("w\twrite table to disk and exit"));
830 puts(_("b\tmove beginning of data in a partition")); /* !sun */
831 puts(_("c\tchange number of cylinders"));
832 puts(_("d\tprint the raw data in the partition table"));
833 puts(_("e\tlist extended partitions")); /* !sun */
834 puts(_("f\tfix partition order")); /* !sun, !aix, !sgi */
835 #if ENABLE_FEATURE_SGI_LABEL
836 puts(_("g\tcreate an IRIX (SGI) partition table"));/* sgi */
838 puts(_("h\tchange number of heads"));
839 puts(_("p\tprint the partition table"));
840 puts(_("q\tquit without saving changes"));
841 puts(_("r\treturn to main menu"));
842 puts(_("s\tchange number of sectors/track"));
843 puts(_("v\tverify the partition table"));
844 puts(_("w\twrite table to disk and exit"));
847 #endif /* ADVANCED mode */
849 #if ENABLE_FEATURE_FDISK_WRITABLE
850 static const struct systypes *
854 LABEL_IS_SUN ? sun_sys_types :
855 LABEL_IS_SGI ? sgi_sys_types :
859 #define get_sys_types() i386_sys_types
860 #endif /* FEATURE_FDISK_WRITABLE */
862 static const char *partition_type(unsigned char type)
865 const struct systypes *types = get_sys_types();
867 for (i = 0; types[i].name; i++)
868 if ((unsigned char)types[i].name[0] == type)
869 return types[i].name + 1;
875 #if ENABLE_FEATURE_FDISK_WRITABLE
879 return LABEL_IS_SUN ? sunlabel->infos[i].id :
880 (LABEL_IS_SGI ? sgi_get_sysid(i) :
881 ptes[i].part_table->sys_ind);
884 static void list_types(const struct systypes *sys)
889 unsigned done, next, size;
892 for (size = 0; sys[size].name; size++) /* */;
895 for (i = COLS-1; i >= 0; i--) {
896 done += (size + i - done) / (i + 1);
897 last[COLS-1 - i] = done;
902 printf("%c%2x %-22.22s", i ? ' ' : '\n',
903 (unsigned char)sys[next].name[0],
905 next = last[i++] + done;
906 if (i >= COLS || next >= last[i]) {
910 } while (done < last[0]);
913 #endif /* FEATURE_FDISK_WRITABLE */
916 is_cleared_partition(const struct partition *p)
918 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
919 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
920 get_start_sect(p) || get_nr_sects(p));
924 clear_partition(struct partition *p)
928 memset(p, 0, sizeof(struct partition));
931 #if ENABLE_FEATURE_FDISK_WRITABLE
933 set_partition(int i, int doext, off_t start, off_t stop, int sysid)
939 p = ptes[i].ext_pointer;
940 offset = extended_offset;
942 p = ptes[i].part_table;
943 offset = ptes[i].offset;
947 set_start_sect(p, start - offset);
948 set_nr_sects(p, stop - start + 1);
949 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
950 start = heads*sectors*1024 - 1;
951 set_hsc(p->head, p->sector, p->cyl, start);
952 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
953 stop = heads*sectors*1024 - 1;
954 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
960 test_c(const char **m, const char *mesg)
964 printf(_("You must set"));
976 const char *m = NULL;
980 prev = test_c(&m, _("heads"));
982 prev = test_c(&m, _("sectors"));
984 prev = test_c(&m, _("cylinders"));
989 #if ENABLE_FEATURE_FDISK_WRITABLE
990 "You can do this from the extra functions menu.\n"
992 , prev ? _(" and ") : " ", m);
1000 int cyl_units = heads * sectors;
1002 if (display_in_cyl_units && cyl_units)
1003 units_per_sector = cyl_units;
1005 units_per_sector = 1; /* in sectors */
1008 #if ENABLE_FEATURE_FDISK_WRITABLE
1010 warn_cylinders(void)
1012 if (LABEL_IS_DOS && cylinders > 1024 && !nowarn)
1014 "The number of cylinders for this disk is set to %d.\n"
1015 "There is nothing wrong with that, but this is larger than 1024,\n"
1016 "and could in certain setups cause problems with:\n"
1017 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1018 "2) booting and partitioning software from other OSs\n"
1019 " (e.g., DOS FDISK, OS/2 FDISK)\n"),
1025 read_extended(int ext)
1029 struct partition *p, *q;
1033 pex->ext_pointer = pex->part_table;
1035 p = pex->part_table;
1036 if (!get_start_sect(p)) {
1037 printf(_("Bad offset in primary extended partition\n"));
1041 while (IS_EXTENDED(p->sys_ind)) {
1042 struct pte *pe = &ptes[partitions];
1044 if (partitions >= MAXIMUM_PARTS) {
1045 /* This is not a Linux restriction, but
1046 this program uses arrays of size MAXIMUM_PARTS.
1047 Do not try to 'improve' this test. */
1048 struct pte *pre = &ptes[partitions-1];
1049 #if ENABLE_FEATURE_FDISK_WRITABLE
1050 printf(_("Warning: deleting partitions after %d\n"),
1054 clear_partition(pre->ext_pointer);
1058 read_pte(pe, extended_offset + get_start_sect(p));
1060 if (!extended_offset)
1061 extended_offset = get_start_sect(p);
1063 q = p = pt_offset(pe->sectorbuffer, 0);
1064 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1065 if (IS_EXTENDED(p->sys_ind)) {
1066 if (pe->ext_pointer)
1067 printf(_("Warning: extra link "
1068 "pointer in partition table"
1069 " %d\n"), partitions + 1);
1071 pe->ext_pointer = p;
1072 } else if (p->sys_ind) {
1074 printf(_("Warning: ignoring extra "
1075 "data in partition table"
1076 " %d\n"), partitions + 1);
1082 /* very strange code here... */
1083 if (!pe->part_table) {
1084 if (q != pe->ext_pointer)
1087 pe->part_table = q + 1;
1089 if (!pe->ext_pointer) {
1090 if (q != pe->part_table)
1091 pe->ext_pointer = q;
1093 pe->ext_pointer = q + 1;
1096 p = pe->ext_pointer;
1100 #if ENABLE_FEATURE_FDISK_WRITABLE
1101 /* remove empty links */
1103 for (i = 4; i < partitions; i++) {
1104 struct pte *pe = &ptes[i];
1106 if (!get_nr_sects(pe->part_table) &&
1107 (partitions > 5 || ptes[4].part_table->sys_ind)) {
1108 printf("omitting empty partition (%d)\n", i+1);
1109 delete_partition(i);
1110 goto remove; /* numbering changed */
1116 #if ENABLE_FEATURE_FDISK_WRITABLE
1118 create_doslabel(void)
1123 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
1124 "until you decide to write them. After that, of course, the previous\n"
1125 "content won't be recoverable.\n\n"));
1127 current_label_type = label_dos;
1129 #if ENABLE_FEATURE_OSF_LABEL
1130 possibly_osf_label = 0;
1134 for (i = 510-64; i < 510; i++)
1136 write_part_table_flag(MBRbuffer);
1137 extended_offset = 0;
1138 set_all_unchanged();
1140 get_boot(create_empty_dos);
1142 #endif /* FEATURE_FDISK_WRITABLE */
1145 get_sectorsize(void)
1147 if (!user_set_sector_size) {
1149 if (ioctl(fd, BLKSSZGET, &arg) == 0)
1151 if (sector_size != DEFAULT_SECTOR_SIZE)
1152 printf(_("Note: sector size is %d (not %d)\n"),
1153 sector_size, DEFAULT_SECTOR_SIZE);
1158 get_kernel_geometry(void)
1160 struct hd_geometry geometry;
1162 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
1163 kern_heads = geometry.heads;
1164 kern_sectors = geometry.sectors;
1165 /* never use geometry.cylinders - it is truncated */
1170 get_partition_table_geometry(void)
1172 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1173 struct partition *p;
1174 int i, h, s, hh, ss;
1178 if (!(valid_part_table_flag((char*)bufp)))
1182 for (i = 0; i < 4; i++) {
1183 p = pt_offset(bufp, i);
1184 if (p->sys_ind != 0) {
1185 h = p->end_head + 1;
1186 s = (p->end_sector & 077);
1191 } else if (hh != h || ss != s)
1196 if (!first && !bad) {
1206 unsigned long long bytes; /* really u64 */
1209 sec_fac = sector_size / 512;
1210 #if ENABLE_FEATURE_SUN_LABEL
1211 guess_device_type();
1213 heads = cylinders = sectors = 0;
1214 kern_heads = kern_sectors = 0;
1215 pt_heads = pt_sectors = 0;
1217 get_kernel_geometry();
1218 get_partition_table_geometry();
1220 heads = user_heads ? user_heads :
1221 pt_heads ? pt_heads :
1222 kern_heads ? kern_heads : 255;
1223 sectors = user_sectors ? user_sectors :
1224 pt_sectors ? pt_sectors :
1225 kern_sectors ? kern_sectors : 63;
1226 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
1229 unsigned long longsectors;
1231 if (ioctl(fd, BLKGETSIZE, &longsectors))
1233 bytes = ((unsigned long long) longsectors) << 9;
1236 total_number_of_sectors = (bytes >> 9);
1239 if (dos_compatible_flag)
1240 sector_offset = sectors;
1242 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
1244 cylinders = user_cylinders;
1248 * Read MBR. Returns:
1249 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1250 * 0: found or created label
1254 get_boot(enum action what)
1260 for (i = 0; i < 4; i++) {
1261 struct pte *pe = &ptes[i];
1263 pe->part_table = pt_offset(MBRbuffer, i);
1264 pe->ext_pointer = NULL;
1266 pe->sectorbuffer = MBRbuffer;
1267 #if ENABLE_FEATURE_FDISK_WRITABLE
1268 pe->changed = (what == create_empty_dos);
1272 #if ENABLE_FEATURE_SUN_LABEL
1273 if (what == create_empty_sun && check_sun_label())
1277 memset(MBRbuffer, 0, 512);
1279 #if ENABLE_FEATURE_FDISK_WRITABLE
1280 if (what == create_empty_dos)
1281 goto got_dos_table; /* skip reading disk */
1283 if ((fd = open(disk_device, type_open)) < 0) {
1284 if ((fd = open(disk_device, O_RDONLY)) < 0) {
1285 if (what == try_only)
1287 fdisk_fatal(unable_to_open);
1289 printf(_("You will not be able to write "
1290 "the partition table.\n"));
1293 if (512 != read(fd, MBRbuffer, 512)) {
1294 if (what == try_only)
1296 fdisk_fatal(unable_to_read);
1299 if ((fd = open(disk_device, O_RDONLY)) < 0)
1301 if (512 != read(fd, MBRbuffer, 512))
1309 #if ENABLE_FEATURE_SUN_LABEL
1310 if (check_sun_label())
1314 #if ENABLE_FEATURE_SGI_LABEL
1315 if (check_sgi_label())
1319 #if ENABLE_FEATURE_AIX_LABEL
1320 if (check_aix_label())
1324 #if ENABLE_FEATURE_OSF_LABEL
1325 if (check_osf_label()) {
1326 possibly_osf_label = 1;
1327 if (!valid_part_table_flag(MBRbuffer)) {
1328 current_label_type = label_osf;
1331 printf(_("This disk has both DOS and BSD magic.\n"
1332 "Give the 'b' command to go to BSD mode.\n"));
1336 #if ENABLE_FEATURE_FDISK_WRITABLE
1340 if (!valid_part_table_flag(MBRbuffer)) {
1341 #if !ENABLE_FEATURE_FDISK_WRITABLE
1346 printf(_("Device contains neither a valid DOS "
1347 "partition table, nor Sun, SGI or OSF "
1350 #if ENABLE_FEATURE_SUN_LABEL
1359 case create_empty_dos:
1360 #if ENABLE_FEATURE_SUN_LABEL
1361 case create_empty_sun:
1365 bb_error_msg_and_die(_("internal error"));
1367 #endif /* FEATURE_FDISK_WRITABLE */
1370 #if ENABLE_FEATURE_FDISK_WRITABLE
1375 for (i = 0; i < 4; i++) {
1376 struct pte *pe = &ptes[i];
1378 if (IS_EXTENDED(pe->part_table->sys_ind)) {
1379 if (partitions != 4)
1380 printf(_("Ignoring extra extended "
1381 "partition %d\n"), i + 1);
1387 for (i = 3; i < partitions; i++) {
1388 struct pte *pe = &ptes[i];
1390 if (!valid_part_table_flag(pe->sectorbuffer)) {
1391 printf(_("Warning: invalid flag 0x%02x,0x%02x of partition "
1392 "table %d will be corrected by w(rite)\n"),
1393 pe->sectorbuffer[510],
1394 pe->sectorbuffer[511],
1396 #if ENABLE_FEATURE_FDISK_WRITABLE
1405 #if ENABLE_FEATURE_FDISK_WRITABLE
1407 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1408 * If the user hits Enter, DFLT is returned.
1409 * Answers like +10 are interpreted as offsets from BASE.
1411 * There is no default if DFLT is not between LOW and HIGH.
1414 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1418 const char *fmt = "%s (%u-%u, default %u): ";
1420 if (dflt < low || dflt > high) {
1421 fmt = "%s (%u-%u): ";
1426 int use_default = default_ok;
1428 /* ask question and read answer */
1430 printf(fmt, mesg, low, high, dflt);
1431 read_maybe_empty("");
1432 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1433 && *line_ptr != '-' && *line_ptr != '+');
1435 if (*line_ptr == '+' || *line_ptr == '-') {
1436 int minus = (*line_ptr == '-');
1439 i = atoi(line_ptr + 1);
1441 while (isdigit(*++line_ptr))
1444 switch (*line_ptr) {
1447 if (!display_in_cyl_units)
1448 i *= heads * sectors;
1462 absolute = 1000000000;
1468 unsigned long long bytes;
1471 bytes = (unsigned long long) i * absolute;
1472 unit = sector_size * units_per_sector;
1473 bytes += unit/2; /* round */
1482 while (isdigit(*line_ptr)) {
1488 printf(_("Using default value %u\n"), i = dflt);
1489 if (i >= low && i <= high)
1492 printf(_("Value is out of range\n"));
1498 get_partition(int warn, int max)
1503 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
1507 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1508 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1509 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1511 printf(_("Warning: partition %d has empty type\n"), i+1);
1518 get_existing_partition(int warn, int max)
1523 for (i = 0; i < max; i++) {
1524 struct pte *pe = &ptes[i];
1525 struct partition *p = pe->part_table;
1527 if (p && !is_cleared_partition(p)) {
1534 printf(_("Selected partition %d\n"), pno+1);
1537 printf(_("No partition is defined yet!\n"));
1541 return get_partition(warn, max);
1545 get_nonexisting_partition(int warn, int max)
1550 for (i = 0; i < max; i++) {
1551 struct pte *pe = &ptes[i];
1552 struct partition *p = pe->part_table;
1554 if (p && is_cleared_partition(p)) {
1561 printf(_("Selected partition %d\n"), pno+1);
1564 printf(_("All primary partitions have been defined already!\n"));
1568 return get_partition(warn, max);
1575 display_in_cyl_units = !display_in_cyl_units;
1577 printf(_("Changing display/entry units to %s\n"),
1582 toggle_active(int i)
1584 struct pte *pe = &ptes[i];
1585 struct partition *p = pe->part_table;
1587 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1588 printf(_("WARNING: Partition %d is an extended partition\n"), i + 1);
1589 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1594 toggle_dos_compatibility_flag(void)
1596 dos_compatible_flag = ~dos_compatible_flag;
1597 if (dos_compatible_flag) {
1598 sector_offset = sectors;
1599 printf(_("DOS Compatibility flag is set\n"));
1603 printf(_("DOS Compatibility flag is not set\n"));
1608 delete_partition(int i)
1610 struct pte *pe = &ptes[i];
1611 struct partition *p = pe->part_table;
1612 struct partition *q = pe->ext_pointer;
1614 /* Note that for the fifth partition (i == 4) we don't actually
1615 * decrement partitions.
1618 if (warn_geometry())
1619 return; /* C/H/S not set */
1623 sun_delete_partition(i);
1627 sgi_delete_partition(i);
1632 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1634 ptes[ext_index].ext_pointer = NULL;
1635 extended_offset = 0;
1641 if (!q->sys_ind && i > 4) {
1642 /* the last one in the chain - just delete */
1645 clear_partition(ptes[i].ext_pointer);
1646 ptes[i].changed = 1;
1648 /* not the last one - further ones will be moved down */
1650 /* delete this link in the chain */
1651 p = ptes[i-1].ext_pointer;
1653 set_start_sect(p, get_start_sect(q));
1654 set_nr_sects(p, get_nr_sects(q));
1655 ptes[i-1].changed = 1;
1656 } else if (partitions > 5) { /* 5 will be moved to 4 */
1657 /* the first logical in a longer chain */
1660 if (pe->part_table) /* prevent SEGFAULT */
1661 set_start_sect(pe->part_table,
1662 get_partition_start(pe) -
1664 pe->offset = extended_offset;
1668 if (partitions > 5) {
1670 while (i < partitions) {
1671 ptes[i] = ptes[i+1];
1675 /* the only logical: clear only */
1676 clear_partition(ptes[i].part_table);
1683 int i, sys, origsys;
1684 struct partition *p;
1686 /* If sgi_label then don't use get_existing_partition,
1687 let the user select a partition, since get_existing_partition()
1688 only works for Linux like partition tables. */
1689 if (!LABEL_IS_SGI) {
1690 i = get_existing_partition(0, partitions);
1692 i = get_partition(0, partitions);
1696 p = ptes[i].part_table;
1697 origsys = sys = get_sysid(i);
1699 /* if changing types T to 0 is allowed, then
1700 the reverse change must be allowed, too */
1701 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1702 printf(_("Partition %d does not exist yet!\n"), i + 1);
1706 sys = read_hex (get_sys_types());
1708 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1709 printf(_("Type 0 means free space to many systems\n"
1710 "(but not to Linux). Having partitions of\n"
1711 "type 0 is probably unwise. You can delete\n"
1712 "a partition using the 'd' command.\n"));
1716 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1717 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1718 printf(_("You cannot change a partition into"
1719 " an extended one or vice versa\n"
1720 "Delete it first.\n"));
1726 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1727 printf(_("Consider leaving partition 3 "
1728 "as Whole disk (5),\n"
1729 "as SunOS/Solaris expects it and "
1730 "even Linux likes it.\n\n"));
1733 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1734 (i == 8 && sys != 0)
1737 printf(_("Consider leaving partition 9 "
1738 "as volume header (0),\nand "
1739 "partition 11 as entire volume (6)"
1740 "as IRIX expects it.\n\n"));
1745 sun_change_sysid(i, sys);
1746 } else if (LABEL_IS_SGI) {
1747 sgi_change_sysid(i, sys);
1751 printf(_("Changed system type of partition %d "
1752 "to %x (%s)\n"), i + 1, sys,
1753 partition_type(sys));
1754 ptes[i].changed = 1;
1755 if (is_dos_partition(origsys) ||
1756 is_dos_partition(sys))
1762 #endif /* FEATURE_FDISK_WRITABLE */
1765 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1766 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1767 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1768 * Lubkin Oct. 1991). */
1771 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1773 int spc = heads * sectors;
1778 *s = ls % sectors + 1; /* sectors count from 1 */
1782 check_consistency(const struct partition *p, int partition)
1784 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1785 unsigned pec, peh, pes; /* physical ending c, h, s */
1786 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1787 unsigned lec, leh, les; /* logical ending c, h, s */
1789 if (!heads || !sectors || (partition >= 4))
1790 return; /* do not check extended partitions */
1792 /* physical beginning c, h, s */
1793 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1795 pbs = p->sector & 0x3f;
1797 /* physical ending c, h, s */
1798 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1800 pes = p->end_sector & 0x3f;
1802 /* compute logical beginning (c, h, s) */
1803 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1805 /* compute logical ending (c, h, s) */
1806 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1808 /* Same physical / logical beginning? */
1809 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1810 printf(_("Partition %d has different physical/logical "
1811 "beginnings (non-Linux?):\n"), partition + 1);
1812 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
1813 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
1816 /* Same physical / logical ending? */
1817 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1818 printf(_("Partition %d has different physical/logical "
1819 "endings:\n"), partition + 1);
1820 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
1821 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
1824 /* Ending on cylinder boundary? */
1825 if (peh != (heads - 1) || pes != sectors) {
1826 printf(_("Partition %i does not end on cylinder boundary.\n"),
1832 list_disk_geometry(void)
1834 long long bytes = (total_number_of_sectors << 9);
1835 long megabytes = bytes/1000000;
1837 if (megabytes < 10000)
1838 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
1839 disk_device, megabytes, bytes);
1841 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
1842 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1843 printf(_("%d heads, %d sectors/track, %d cylinders"),
1844 heads, sectors, cylinders);
1845 if (units_per_sector == 1)
1846 printf(_(", total %llu sectors"),
1847 total_number_of_sectors / (sector_size/512));
1848 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
1850 units_per_sector, sector_size, units_per_sector * sector_size);
1854 * Check whether partition entries are ordered by their starting positions.
1855 * Return 0 if OK. Return i if partition i should have been earlier.
1856 * Two separate checks: primary and logical partitions.
1859 wrong_p_order(int *prev)
1861 const struct pte *pe;
1862 const struct partition *p;
1863 off_t last_p_start_pos = 0, p_start_pos;
1866 for (i = 0 ; i < partitions; i++) {
1869 last_p_start_pos = 0;
1872 if ((p = pe->part_table)->sys_ind) {
1873 p_start_pos = get_partition_start(pe);
1875 if (last_p_start_pos > p_start_pos) {
1881 last_p_start_pos = p_start_pos;
1888 #if ENABLE_FEATURE_FDISK_ADVANCED
1890 * Fix the chain of logicals.
1891 * extended_offset is unchanged, the set of sectors used is unchanged
1892 * The chain is sorted so that sectors increase, and so that
1893 * starting sectors increase.
1895 * After this it may still be that cfdisk doesnt like the table.
1896 * (This is because cfdisk considers expanded parts, from link to
1897 * end of partition, and these may still overlap.)
1899 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1903 fix_chain_of_logicals(void)
1905 int j, oj, ojj, sj, sjj;
1906 struct partition *pj,*pjj,tmp;
1908 /* Stage 1: sort sectors but leave sector of part 4 */
1909 /* (Its sector is the global extended_offset.) */
1911 for (j = 5; j < partitions-1; j++) {
1912 oj = ptes[j].offset;
1913 ojj = ptes[j+1].offset;
1915 ptes[j].offset = ojj;
1916 ptes[j+1].offset = oj;
1917 pj = ptes[j].part_table;
1918 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1919 pjj = ptes[j+1].part_table;
1920 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1921 set_start_sect(ptes[j-1].ext_pointer,
1922 ojj-extended_offset);
1923 set_start_sect(ptes[j].ext_pointer,
1924 oj-extended_offset);
1929 /* Stage 2: sort starting sectors */
1931 for (j = 4; j < partitions-1; j++) {
1932 pj = ptes[j].part_table;
1933 pjj = ptes[j+1].part_table;
1934 sj = get_start_sect(pj);
1935 sjj = get_start_sect(pjj);
1936 oj = ptes[j].offset;
1937 ojj = ptes[j+1].offset;
1938 if (oj+sj > ojj+sjj) {
1942 set_start_sect(pj, ojj+sjj-oj);
1943 set_start_sect(pjj, oj+sj-ojj);
1948 /* Probably something was changed */
1949 for (j = 4; j < partitions; j++)
1950 ptes[j].changed = 1;
1955 fix_partition_table_order(void)
1957 struct pte *pei, *pek;
1960 if (!wrong_p_order(NULL)) {
1961 printf(_("Nothing to do. Ordering is correct already.\n\n"));
1965 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1966 /* partition i should have come earlier, move it */
1967 /* We have to move data in the MBR */
1968 struct partition *pi, *pk, *pe, pbuf;
1972 pe = pei->ext_pointer;
1973 pei->ext_pointer = pek->ext_pointer;
1974 pek->ext_pointer = pe;
1976 pi = pei->part_table;
1977 pk = pek->part_table;
1979 memmove(&pbuf, pi, sizeof(struct partition));
1980 memmove(pi, pk, sizeof(struct partition));
1981 memmove(pk, &pbuf, sizeof(struct partition));
1983 pei->changed = pek->changed = 1;
1987 fix_chain_of_logicals();
1995 list_table(int xtra)
1997 const struct partition *p;
2001 sun_list_table(xtra);
2005 sgi_list_table(xtra);
2009 list_disk_geometry();
2012 xbsd_print_disklabel(xtra);
2016 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2017 but if the device name ends in a digit, say /dev/foo1,
2018 then the partition is called /dev/foo1p3. */
2019 w = strlen(disk_device);
2020 if (w && isdigit(disk_device[w-1]))
2025 // 1 12345678901 12345678901 12345678901 12
2026 printf(_("%*s Boot Start End Blocks Id System\n"),
2029 for (i = 0; i < partitions; i++) {
2030 const struct pte *pe = &ptes[i];
2036 if (!p || is_cleared_partition(p))
2039 psects = get_nr_sects(p);
2043 if (sector_size < 1024) {
2044 pblocks /= (1024 / sector_size);
2045 podd = psects % (1024 / sector_size);
2047 if (sector_size > 1024)
2048 pblocks *= (sector_size / 1024);
2050 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2051 partname(disk_device, i+1, w+2),
2052 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2054 (unsigned long long) cround(get_partition_start(pe)), /* start */
2055 (unsigned long long) cround(get_partition_start(pe) + psects /* end */
2056 - (psects ? 1 : 0)),
2057 (unsigned long long) pblocks, podd ? '+' : ' ', /* odd flag on end */
2058 p->sys_ind, /* type id */
2059 partition_type(p->sys_ind)); /* type name */
2061 check_consistency(p, i);
2064 /* Is partition table in disk order? It need not be, but... */
2065 /* partition table entries are not checked for correct order if this
2066 is a sgi, sun or aix labeled disk... */
2067 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2069 printf(_("\nPartition table entries are not in disk order\n"));
2073 #if ENABLE_FEATURE_FDISK_ADVANCED
2075 x_list_table(int extend)
2077 const struct pte *pe;
2078 const struct partition *p;
2081 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
2082 disk_device, heads, sectors, cylinders);
2083 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
2084 for (i = 0 ; i < partitions; i++) {
2086 p = (extend ? pe->ext_pointer : pe->part_table);
2088 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2089 i + 1, p->boot_ind, p->head,
2091 cylinder(p->sector, p->cyl), p->end_head,
2092 sector(p->end_sector),
2093 cylinder(p->end_sector, p->end_cyl),
2094 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2096 check_consistency(p, i);
2102 #if ENABLE_FEATURE_FDISK_WRITABLE
2104 fill_bounds(off_t *first, off_t *last)
2107 const struct pte *pe = &ptes[0];
2108 const struct partition *p;
2110 for (i = 0; i < partitions; pe++,i++) {
2112 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2113 first[i] = 0xffffffff;
2116 first[i] = get_partition_start(pe);
2117 last[i] = first[i] + get_nr_sects(p) - 1;
2123 check(int n, unsigned h, unsigned s, unsigned c, off_t start)
2125 off_t total, real_s, real_c;
2127 real_s = sector(s) - 1;
2128 real_c = cylinder(s, c);
2129 total = (real_c * sectors + real_s) * heads + h;
2131 printf(_("Warning: partition %d contains sector 0\n"), n);
2133 printf(_("Partition %d: head %d greater than maximum %d\n"),
2135 if (real_s >= sectors)
2136 printf(_("Partition %d: sector %d greater than "
2137 "maximum %d\n"), n, s, sectors);
2138 if (real_c >= cylinders)
2139 printf(_("Partitions %d: cylinder %llu greater than "
2140 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
2141 if (cylinders <= 1024 && start != total)
2142 printf(_("Partition %d: previous sectors %llu disagrees with "
2143 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
2151 off_t first[partitions], last[partitions];
2152 struct partition *p;
2154 if (warn_geometry())
2166 fill_bounds(first, last);
2167 for (i = 0; i < partitions; i++) {
2168 struct pte *pe = &ptes[i];
2171 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2172 check_consistency(p, i);
2173 if (get_partition_start(pe) < first[i])
2174 printf(_("Warning: bad start-of-data in "
2175 "partition %d\n"), i + 1);
2176 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2178 total += last[i] + 1 - first[i];
2179 for (j = 0; j < i; j++)
2180 if ((first[i] >= first[j] && first[i] <= last[j])
2181 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2182 printf(_("Warning: partition %d overlaps "
2183 "partition %d.\n"), j + 1, i + 1);
2184 total += first[i] >= first[j] ?
2185 first[i] : first[j];
2186 total -= last[i] <= last[j] ?
2192 if (extended_offset) {
2193 struct pte *pex = &ptes[ext_index];
2194 off_t e_last = get_start_sect(pex->part_table) +
2195 get_nr_sects(pex->part_table) - 1;
2197 for (i = 4; i < partitions; i++) {
2199 p = ptes[i].part_table;
2201 if (i != 4 || i + 1 < partitions)
2202 printf(_("Warning: partition %d "
2203 "is empty\n"), i + 1);
2205 else if (first[i] < extended_offset ||
2207 printf(_("Logical partition %d not entirely in "
2208 "partition %d\n"), i + 1, ext_index + 1);
2212 if (total > heads * sectors * cylinders)
2213 printf(_("Total allocated sectors %d greater than the maximum "
2214 "%d\n"), total, heads * sectors * cylinders);
2215 else if ((total = heads * sectors * cylinders - total) != 0)
2216 printf(_("%d unallocated sectors\n"), total);
2220 add_partition(int n, int sys)
2222 char mesg[256]; /* 48 does not suffice in Japanese */
2223 int i, num_read = 0;
2224 struct partition *p = ptes[n].part_table;
2225 struct partition *q = ptes[ext_index].part_table;
2227 off_t start, stop = 0, limit, temp,
2228 first[partitions], last[partitions];
2230 if (p && p->sys_ind) {
2231 printf(_("Partition %d is already defined. Delete "
2232 "it before re-adding it.\n"), n + 1);
2235 fill_bounds(first, last);
2237 start = sector_offset;
2238 if (display_in_cyl_units || !total_number_of_sectors)
2239 llimit = heads * sectors * cylinders - 1;
2241 llimit = total_number_of_sectors - 1;
2243 if (limit != llimit)
2245 if (extended_offset) {
2246 first[ext_index] = extended_offset;
2247 last[ext_index] = get_start_sect(q) +
2248 get_nr_sects(q) - 1;
2251 start = extended_offset + sector_offset;
2252 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2254 if (display_in_cyl_units)
2255 for (i = 0; i < partitions; i++)
2256 first[i] = (cround(first[i]) - 1) * units_per_sector;
2258 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2261 for (i = 0; i < partitions; i++) {
2264 if (start == ptes[i].offset)
2265 start += sector_offset;
2266 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2267 if (start >= first[i] && start <= lastplusoff)
2268 start = lastplusoff + 1;
2272 if (start >= temp+units_per_sector && num_read) {
2273 printf(_("Sector %"OFF_FMT"d is already allocated\n"), temp);
2277 if (!num_read && start == temp) {
2280 saved_start = start;
2281 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2283 if (display_in_cyl_units) {
2284 start = (start - 1) * units_per_sector;
2285 if (start < saved_start) start = saved_start;
2289 } while (start != temp || !num_read);
2290 if (n > 4) { /* NOT for fifth partition */
2291 struct pte *pe = &ptes[n];
2293 pe->offset = start - sector_offset;
2294 if (pe->offset == extended_offset) { /* must be corrected */
2296 if (sector_offset == 1)
2301 for (i = 0; i < partitions; i++) {
2302 struct pte *pe = &ptes[i];
2304 if (start < pe->offset && limit >= pe->offset)
2305 limit = pe->offset - 1;
2306 if (start < first[i] && limit >= first[i])
2307 limit = first[i] - 1;
2309 if (start > limit) {
2310 printf(_("No free sectors available\n"));
2315 if (cround(start) == cround(limit)) {
2318 snprintf(mesg, sizeof(mesg),
2319 _("Last %s or +size or +sizeM or +sizeK"),
2320 str_units(SINGULAR));
2321 stop = read_int(cround(start), cround(limit), cround(limit),
2322 cround(start), mesg);
2323 if (display_in_cyl_units) {
2324 stop = stop * units_per_sector - 1;
2330 set_partition(n, 0, start, stop, sys);
2332 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2334 if (IS_EXTENDED(sys)) {
2335 struct pte *pe4 = &ptes[4];
2336 struct pte *pen = &ptes[n];
2339 pen->ext_pointer = p;
2340 pe4->offset = extended_offset = start;
2341 pe4->sectorbuffer = xzalloc(sector_size);
2342 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2343 pe4->ext_pointer = pe4->part_table + 1;
2352 if (partitions > 5 || ptes[4].part_table->sys_ind) {
2353 struct pte *pe = &ptes[partitions];
2355 pe->sectorbuffer = xzalloc(sector_size);
2356 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2357 pe->ext_pointer = pe->part_table + 1;
2362 add_partition(partitions - 1, LINUX_NATIVE);
2368 int i, free_primary = 0;
2370 if (warn_geometry())
2374 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
2378 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
2382 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
2383 "\n\tIf you want to add DOS-type partitions, create"
2384 "\n\ta new empty DOS partition table first. (Use o.)"
2386 "This will destroy the present disk contents.\n"));
2390 for (i = 0; i < 4; i++)
2391 free_primary += !ptes[i].part_table->sys_ind;
2393 if (!free_primary && partitions >= MAXIMUM_PARTS) {
2394 printf(_("The maximum number of partitions has been created\n"));
2398 if (!free_primary) {
2399 if (extended_offset)
2402 printf(_("You must delete some partition and add "
2403 "an extended partition first\n"));
2405 char c, line[LINE_LENGTH];
2406 snprintf(line, sizeof(line),
2409 " p primary partition (1-4)\n",
2411 "l logical (5 or over)" : "e extended"));
2413 c = read_nonempty(line);
2414 if (c == 'p' || c == 'P') {
2415 i = get_nonexisting_partition(0, 4);
2417 add_partition(i, LINUX_NATIVE);
2420 else if (c == 'l' && extended_offset) {
2424 else if (c == 'e' && !extended_offset) {
2425 i = get_nonexisting_partition(0, 4);
2427 add_partition(i, EXTENDED);
2431 printf(_("Invalid partition number "
2432 "for type '%c'\n"), c);
2443 for (i = 0; i < 3; i++)
2444 if (ptes[i].changed)
2445 ptes[3].changed = 1;
2446 for (i = 3; i < partitions; i++) {
2447 struct pte *pe = &ptes[i];
2450 write_part_table_flag(pe->sectorbuffer);
2451 write_sector(pe->offset, pe->sectorbuffer);
2455 else if (LABEL_IS_SGI) {
2456 /* no test on change? the printf below might be mistaken */
2459 else if (LABEL_IS_SUN) {
2462 for (i = 0; i < 8; i++)
2463 if (ptes[i].changed)
2469 printf(_("The partition table has been altered!\n\n"));
2470 reread_partition_table(1);
2474 reread_partition_table(int leave)
2478 printf(_("Calling ioctl() to re-read partition table\n"));
2480 sleep(2); /* Huh? */
2481 i = ioctl(fd, BLKRRPART);
2484 /* some kernel versions (1.2.x) seem to have trouble
2485 rereading the partition table, but if asked to do it
2486 twice, the second time works. - biro@yggdrasil.com */
2489 i = ioctl(fd, BLKRRPART);
2494 bb_perror_msg("WARNING: rereading partition table "
2495 "failed, kernel still uses old table");
2501 _("\nWARNING: If you have created or modified any DOS 6.x\n"
2502 "partitions, please see the fdisk manual page for additional\n"
2507 if (ENABLE_FEATURE_CLEAN_UP)
2512 #endif /* FEATURE_FDISK_WRITABLE */
2514 #if ENABLE_FEATURE_FDISK_ADVANCED
2515 #define MAX_PER_LINE 16
2517 print_buffer(char *pbuffer)
2521 for (i = 0, l = 0; i < sector_size; i++, l++) {
2523 printf("0x%03X:", i);
2524 printf(" %02X", (unsigned char) pbuffer[i]);
2525 if (l == MAX_PER_LINE - 1) {
2540 printf(_("Device: %s\n"), disk_device);
2541 if (LABEL_IS_SGI || LABEL_IS_SUN)
2542 print_buffer(MBRbuffer);
2544 for (i = 3; i < partitions; i++)
2545 print_buffer(ptes[i].sectorbuffer);
2552 struct pte *pe = &ptes[i];
2553 struct partition *p = pe->part_table;
2556 if (warn_geometry())
2558 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2559 printf(_("Partition %d has no data area\n"), i + 1);
2562 first = get_partition_start(pe);
2563 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2564 _("New beginning of data")) - pe->offset;
2566 if (new != get_nr_sects(p)) {
2567 first = get_nr_sects(p) + get_start_sect(p) - new;
2568 set_nr_sects(p, first);
2569 set_start_sect(p, new);
2581 c = tolower(read_nonempty(_("Expert command (m for help): ")));
2589 move_begin(get_partition(0, partitions));
2592 user_cylinders = cylinders =
2593 read_int(1, cylinders, 1048576, 0,
2594 _("Number of cylinders"));
2596 sun_set_ncyl(cylinders);
2606 else if (LABEL_IS_SUN)
2608 else if (LABEL_IS_DOS)
2613 fix_partition_table_order();
2616 #if ENABLE_FEATURE_SGI_LABEL
2621 user_heads = heads = read_int(1, heads, 256, 0,
2622 _("Number of heads"));
2646 user_sectors = sectors = read_int(1, sectors, 63, 0,
2647 _("Number of sectors"));
2648 if (dos_compatible_flag) {
2649 sector_offset = sectors;
2650 printf(_("Warning: setting sector offset for DOS "
2659 write_table(); /* does not return */
2663 sun_set_pcylcount();
2670 #endif /* ADVANCED mode */
2673 is_ide_cdrom_or_tape(const char *device)
2677 struct stat statbuf;
2680 /* No device was given explicitly, and we are trying some
2681 likely things. But opening /dev/hdc may produce errors like
2682 "hdc: tray open or drive not ready"
2683 if it happens to be a CD-ROM drive. It even happens that
2684 the process hangs on the attempt to read a music CD.
2685 So try to be careful. This only works since 2.1.73. */
2687 if (strncmp("/dev/hd", device, 7))
2690 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2691 procf = fopen(buf, "r");
2692 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2693 is_ide = (!strncmp(buf, "cdrom", 5) ||
2694 !strncmp(buf, "tape", 4));
2696 /* Now when this proc file does not exist, skip the
2697 device when it is read-only. */
2698 if (stat(device, &statbuf) == 0)
2699 is_ide = ((statbuf.st_mode & 0222) == 0);
2708 trydev(const char *device, int user_specified)
2712 disk_device = device;
2713 if (setjmp(listingbuf))
2715 if (!user_specified)
2716 if (is_ide_cdrom_or_tape(device))
2718 fd = open(disk_device, type_open);
2720 gb = get_boot(try_only);
2721 if (gb > 0) { /* I/O error */
2723 } else if (gb < 0) { /* no DOS signature */
2724 list_disk_geometry();
2728 #if ENABLE_FEATURE_OSF_LABEL
2729 if (bsd_trydev(device) < 0)
2731 printf(_("Disk %s doesn't contain a valid "
2732 "partition table\n"), device);
2737 #if ENABLE_FEATURE_FDISK_WRITABLE
2738 if (!LABEL_IS_SUN && partitions > 4){
2739 delete_partition(ext_index);
2744 /* Ignore other errors, since we try IDE
2745 and SCSI hard disks which may not be
2746 installed on the system. */
2747 if (errno == EACCES) {
2748 printf(_("Cannot open %s\n"), device);
2754 /* for fdisk -l: try all things in /proc/partitions
2755 that look like a partition name (do not end in a digit) */
2760 char line[100], ptname[100], devname[120], *s;
2763 procpt = fopen_or_warn("/proc/partitions", "r");
2765 while (fgets(line, sizeof(line), procpt)) {
2766 if (sscanf(line, " %d %d %d %[^\n ]",
2767 &ma, &mi, &sz, ptname) != 4)
2769 for (s = ptname; *s; s++);
2772 sprintf(devname, "/dev/%s", ptname);
2775 #if ENABLE_FEATURE_CLEAN_UP
2780 #if ENABLE_FEATURE_FDISK_WRITABLE
2782 unknown_command(int c)
2784 printf(_("%c: unknown command\n"), c);
2788 void BUG_fdisk_globals_overflow(void);
2790 int fdisk_main(int argc, char **argv);
2791 int fdisk_main(int argc, char **argv)
2793 char *str_b, *str_C, *str_H, *str_S;
2797 * fdisk -l [-b sectorsize] [-u] device ...
2798 * fdisk -s [partition] ...
2799 * fdisk [-b sectorsize] [-u] device
2801 * Options -C, -H, -S set the geometry.
2810 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
2813 if (sizeof(G) > sizeof(bb_common_bufsiz1))
2814 BUG_fdisk_globals_overflow();
2816 opt = getopt32(argc, argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2817 &str_b, &str_C, &str_H, &str_S);
2820 if (opt & OPT_b) { // -b
2821 /* Ugly: this sector size is really per device,
2822 so cannot be combined with multiple disks,
2823 and the same goes for the C/H/S options.
2825 sector_size = xatoi_u(str_b);
2826 if (sector_size != 512 && sector_size != 1024 &&
2827 sector_size != 2048)
2830 user_set_sector_size = 1;
2832 if (opt & OPT_C) user_cylinders = xatoi_u(str_C); // -C
2833 if (opt & OPT_H) { // -H
2834 user_heads = xatoi_u(str_H);
2835 if (user_heads <= 0 || user_heads >= 256)
2838 //if (opt & OPT_l) // -l
2839 if (opt & OPT_S) { // -S
2840 user_sectors = xatoi_u(str_S);
2841 if (user_sectors <= 0 || user_sectors >= 64)
2844 if (opt & OPT_u) display_in_cyl_units = 0; // -u
2845 //if (opt & OPT_s) // -s
2847 if (user_set_sector_size && argc != 1)
2848 printf(_("Warning: the -b (set sector size) option should"
2849 " be used with one specified device\n"));
2851 #if ENABLE_FEATURE_FDISK_WRITABLE
2855 type_open = O_RDONLY;
2858 #if defined(__GNUC__)
2859 /* avoid gcc warning:
2860 variable `k' might be clobbered by `longjmp' */
2864 for (k = 0; k < argc; k++)
2867 /* we no longer have default device names */
2868 /* but, we can use /proc/partitions instead */
2872 #if ENABLE_FEATURE_FDISK_WRITABLE
2876 #if ENABLE_FEATURE_FDISK_BLKSIZE
2882 type_open = O_RDONLY;
2887 for (j = 0; j < argc; j++) {
2888 disk_device = argv[j];
2889 fd = open(disk_device, type_open);
2891 fdisk_fatal(unable_to_open);
2892 if (ioctl(fd, BLKGETSIZE, &size))
2893 fdisk_fatal(ioctl_error);
2896 printf("%ld\n", size/2);
2898 printf("%s: %ld\n", argv[j], size/2);
2904 #if ENABLE_FEATURE_FDISK_WRITABLE
2908 disk_device = argv[0];
2912 /* OSF label, and no DOS label */
2913 printf(_("Detected an OSF/1 disklabel on %s, entering "
2914 "disklabel mode.\n"), disk_device);
2916 /*Why do we do this? It seems to be counter-intuitive*/
2917 current_label_type = label_dos;
2918 /* If we return we may want to make an empty DOS label? */
2924 c = tolower(read_nonempty(_("Command (m for help): ")));
2928 toggle_active(get_partition(1, partitions));
2929 else if (LABEL_IS_SUN)
2930 toggle_sunflags(get_partition(1, partitions),
2932 else if (LABEL_IS_SGI)
2933 sgi_set_bootpartition(
2934 get_partition(1, partitions));
2940 printf(_("\nThe current boot file is: %s\n"),
2941 sgi_get_bootfile());
2942 if (read_maybe_empty(_("Please enter the name of the "
2943 "new boot file: ")) == '\n')
2944 printf(_("Boot file unchanged\n"));
2946 sgi_set_bootfile(line_ptr);
2948 #if ENABLE_FEATURE_OSF_LABEL
2955 toggle_dos_compatibility_flag();
2956 else if (LABEL_IS_SUN)
2957 toggle_sunflags(get_partition(1, partitions),
2959 else if (LABEL_IS_SGI)
2960 sgi_set_swappartition(
2961 get_partition(1, partitions));
2968 /* If sgi_label then don't use get_existing_partition,
2969 let the user select a partition, since
2970 get_existing_partition() only works for Linux-like
2972 if (!LABEL_IS_SGI) {
2973 j = get_existing_partition(1, partitions);
2975 j = get_partition(1, partitions);
2978 delete_partition(j);
2987 list_types(get_sys_types());
3006 #if ENABLE_FEATURE_SUN_LABEL
3020 write_table(); /* does not return */
3022 #if ENABLE_FEATURE_FDISK_ADVANCED
3025 printf(_("\n\tSorry, no experts menu for SGI "
3026 "partition tables available.\n\n"));
3037 #endif /* FEATURE_FDISK_WRITABLE */