1 /* vi: set sw=4 ts=4: */
2 /* fdisk.c -- Partition table manipulator for Linux.
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
10 #ifndef _LARGEFILE64_SOURCE
12 # define _LARGEFILE64_SOURCE
14 #include <assert.h> /* assert */
15 #include <sys/mount.h>
16 #if !defined(BLKSSZGET)
17 # define BLKSSZGET _IO(0x12, 104)
19 #if !defined(BLKGETSIZE64)
20 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
25 # define inline_if_little_endian ALWAYS_INLINE
27 # define inline_if_little_endian /* nothing */
31 /* Looks like someone forgot to add this to config system */
32 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
33 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
34 # define IF_FEATURE_FDISK_BLKSIZE(a)
37 #define DEFAULT_SECTOR_SIZE 512
38 #define DEFAULT_SECTOR_SIZE_STR "512"
39 #define MAX_SECTOR_SIZE 2048
40 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
41 #define MAXIMUM_PARTS 60
43 #define ACTIVE_FLAG 0x80
46 #define WIN98_EXTENDED 0x0f
47 #define LINUX_PARTITION 0x81
48 #define LINUX_SWAP 0x82
49 #define LINUX_NATIVE 0x83
50 #define LINUX_EXTENDED 0x85
51 #define LINUX_LVM 0x8e
52 #define LINUX_RAID 0xfd
62 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
66 typedef unsigned long long ullong;
67 /* Used for sector numbers. Partition formats we know
68 * do not support more than 2^32 sectors
70 typedef uint32_t sector_t;
71 #if UINT_MAX == 4294967295
73 #elif ULONG_MAX == 4294967295
76 # error Cant detect sizeof(uint32_t)
81 unsigned char sectors;
82 unsigned short cylinders;
86 #define HDIO_GETGEO 0x0301 /* get device geometry */
88 static const char msg_building_new_label[] ALIGN1 =
89 "Building a new %s. Changes will remain in memory only,\n"
90 "until you decide to write them. After that the previous content\n"
91 "won't be recoverable.\n\n";
93 static const char msg_part_already_defined[] ALIGN1 =
94 "Partition %u is already defined, delete it before re-adding\n";
98 unsigned char boot_ind; /* 0x80 - active */
99 unsigned char head; /* starting head */
100 unsigned char sector; /* starting sector */
101 unsigned char cyl; /* starting cylinder */
102 unsigned char sys_ind; /* what partition type */
103 unsigned char end_head; /* end head */
104 unsigned char end_sector; /* end sector */
105 unsigned char end_cyl; /* end cylinder */
106 unsigned char start4[4]; /* starting sector counting from 0 */
107 unsigned char size4[4]; /* nr of sectors in partition */
110 #define unable_to_open "can't open '%s'"
111 #define unable_to_read "can't read from %s"
112 #define unable_to_seek "can't seek on %s"
115 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
118 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
120 #if ENABLE_FEATURE_SUN_LABEL
121 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
122 #define STATIC_SUN static
124 #define LABEL_IS_SUN 0
125 #define STATIC_SUN extern
128 #if ENABLE_FEATURE_SGI_LABEL
129 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
130 #define STATIC_SGI static
132 #define LABEL_IS_SGI 0
133 #define STATIC_SGI extern
136 #if ENABLE_FEATURE_AIX_LABEL
137 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
138 #define STATIC_AIX static
140 #define LABEL_IS_AIX 0
141 #define STATIC_AIX extern
144 #if ENABLE_FEATURE_OSF_LABEL
145 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
146 #define STATIC_OSF static
148 #define LABEL_IS_OSF 0
149 #define STATIC_OSF extern
152 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
154 static void update_units(void);
155 #if ENABLE_FEATURE_FDISK_WRITABLE
156 static void change_units(void);
157 static void reread_partition_table(int leave);
158 static void delete_partition(int i);
159 static unsigned get_partition(int warn, unsigned max);
160 static void list_types(const char *const *sys);
161 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
163 static const char *partition_type(unsigned char type);
164 static void get_geometry(void);
165 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
166 static int get_boot(enum action what);
168 static int get_boot(void);
174 static sector_t get_start_sect(const struct partition *p);
175 static sector_t get_nr_sects(const struct partition *p);
178 * per partition table entry data
180 * The four primary partitions have the same sectorbuffer (MBRbuffer)
181 * and have NULL ext_pointer.
182 * Each logical partition table entry has two pointers, one for the
183 * partition and one link to the next one.
186 struct partition *part_table; /* points into sectorbuffer */
187 struct partition *ext_pointer; /* points into sectorbuffer */
188 sector_t offset_from_dev_start; /* disk sector number */
189 char *sectorbuffer; /* disk sector contents */
190 #if ENABLE_FEATURE_FDISK_WRITABLE
191 char changed; /* boolean */
195 /* DOS partition types */
197 static const char *const i386_sys_types[] = {
201 "\x05" "Extended", /* DOS 3.3+ extended partition */
202 "\x06" "FAT16", /* DOS 16-bit >=32M */
203 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
204 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
205 "\x0b" "Win95 FAT32",
206 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
207 "\x0e" "Win95 FAT16 (LBA)",
208 "\x0f" "Win95 Ext'd (LBA)",
209 "\x11" "Hidden FAT12",
210 "\x12" "Compaq diagnostics",
211 "\x14" "Hidden FAT16 <32M",
212 "\x16" "Hidden FAT16",
213 "\x17" "Hidden HPFS/NTFS",
214 "\x1b" "Hidden Win95 FAT32",
215 "\x1c" "Hidden W95 FAT32 (LBA)",
216 "\x1e" "Hidden W95 FAT16 (LBA)",
217 "\x3c" "Part.Magic recovery",
218 "\x41" "PPC PReP Boot",
220 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
221 "\x80" "Old Minix", /* Minix 1.4a and earlier */
222 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
223 "\x82" "Linux swap", /* also Solaris */
225 "\x84" "OS/2 hidden C: drive",
226 "\x85" "Linux extended",
227 "\x86" "NTFS volume set",
228 "\x87" "NTFS volume set",
230 "\x9f" "BSD/OS", /* BSDI */
231 "\xa0" "Thinkpad hibernation",
232 "\xa5" "FreeBSD", /* various BSD flavours */
236 "\xab" "Darwin boot",
239 "\xbe" "Solaris boot",
241 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
242 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
243 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
244 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
245 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
246 autodetect using persistent
248 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
251 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
252 "\x09" "AIX bootable", /* AIX data or Coherent */
254 "\x18" "AST SmartSleep",
257 "\x40" "Venix 80286",
259 "\x4e" "QNX4.x 2nd part",
260 "\x4f" "QNX4.x 3rd part",
262 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
263 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
264 "\x53" "OnTrack DM6 Aux3",
268 "\x5c" "Priam Edisk",
270 "\x64" "Novell Netware 286",
271 "\x65" "Novell Netware 386",
272 "\x70" "DiskSecure Multi-Boot",
275 "\x94" "Amoeba BBT", /* (bad block table) */
277 "\xbb" "Boot Wizard hidden",
278 "\xc1" "DRDOS/sec (FAT-12)",
279 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
280 "\xc6" "DRDOS/sec (FAT-16)",
282 "\xda" "Non-FS data",
283 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
284 Concurrent DOS or CTOS */
285 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
286 "\xdf" "BootIt", /* BootIt EMBRM */
287 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
288 extended partition */
289 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
290 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
291 partition < 1024 cyl. */
293 "\xf4" "SpeedStor", /* SpeedStor large partition */
294 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
295 "\xff" "BBT", /* Xenix Bad Block Table */
301 dev_fd = 3 /* the disk */
308 const char *disk_device;
309 int g_partitions; // = 4; /* maximum partition + 1 */
310 unsigned units_per_sector; // = 1;
311 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
312 unsigned user_set_sector_size;
313 unsigned sector_offset; // = 1;
314 unsigned g_heads, g_sectors, g_cylinders;
315 smallint /* enum label_type */ current_label_type;
316 smallint display_in_cyl_units; // = 1;
317 #if ENABLE_FEATURE_OSF_LABEL
318 smallint possibly_osf_label;
321 smallint listing; /* no aborts for fdisk -l */
322 smallint dos_compatible_flag; // = 1;
323 #if ENABLE_FEATURE_FDISK_WRITABLE
325 smallint nowarn; /* no warnings for fdisk -l/-s */
327 int ext_index; /* the prime extended partition */
328 unsigned user_cylinders, user_heads, user_sectors;
329 unsigned pt_heads, pt_sectors;
330 unsigned kern_heads, kern_sectors;
331 sector_t extended_offset; /* offset of link pointers */
332 sector_t total_number_of_sectors;
335 char line_buffer[80];
336 char partname_buffer[80];
337 /* Raw disk label. For DOS-type partition tables the MBR,
338 * with descriptions of the primary partitions. */
339 char MBRbuffer[MAX_SECTOR_SIZE];
340 /* Partition tables */
341 struct pte ptes[MAXIMUM_PARTS];
343 #define G (*ptr_to_globals)
344 #define line_ptr (G.line_ptr )
345 #define disk_device (G.disk_device )
346 #define g_partitions (G.g_partitions )
347 #define units_per_sector (G.units_per_sector )
348 #define sector_size (G.sector_size )
349 #define user_set_sector_size (G.user_set_sector_size)
350 #define sector_offset (G.sector_offset )
351 #define g_heads (G.g_heads )
352 #define g_sectors (G.g_sectors )
353 #define g_cylinders (G.g_cylinders )
354 #define current_label_type (G.current_label_type )
355 #define display_in_cyl_units (G.display_in_cyl_units)
356 #define possibly_osf_label (G.possibly_osf_label )
357 #define listing (G.listing )
358 #define dos_compatible_flag (G.dos_compatible_flag )
359 #define nowarn (G.nowarn )
360 #define ext_index (G.ext_index )
361 #define user_cylinders (G.user_cylinders )
362 #define user_heads (G.user_heads )
363 #define user_sectors (G.user_sectors )
364 #define pt_heads (G.pt_heads )
365 #define pt_sectors (G.pt_sectors )
366 #define kern_heads (G.kern_heads )
367 #define kern_sectors (G.kern_sectors )
368 #define extended_offset (G.extended_offset )
369 #define total_number_of_sectors (G.total_number_of_sectors)
370 #define listingbuf (G.listingbuf )
371 #define line_buffer (G.line_buffer )
372 #define partname_buffer (G.partname_buffer)
373 #define MBRbuffer (G.MBRbuffer )
374 #define ptes (G.ptes )
375 #define INIT_G() do { \
376 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
377 sector_size = DEFAULT_SECTOR_SIZE; \
380 display_in_cyl_units = 1; \
381 units_per_sector = 1; \
382 dos_compatible_flag = 1; \
386 /* TODO: move to libbb? */
387 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
388 * disks > 2^32 sectors
390 static sector_t bb_BLKGETSIZE_sectors(int fd)
393 unsigned long longsectors;
395 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
396 /* Got bytes, convert to 512 byte sectors */
398 if (v64 != (sector_t)v64) {
400 /* Not only DOS, but all other partition tables
401 * we support can't record more than 32 bit
402 * sector counts or offsets
404 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
409 /* Needs temp of type long */
410 if (ioctl(fd, BLKGETSIZE, &longsectors)) {
411 /* Perhaps this is a disk image */
412 off_t sz = lseek(fd, 0, SEEK_END);
415 longsectors = (uoff_t)sz / sector_size;
416 lseek(fd, 0, SEEK_SET);
418 if (sizeof(long) > sizeof(sector_t)
419 && longsectors != (sector_t)longsectors
427 #define IS_EXTENDED(i) \
428 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
430 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
432 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
434 #define pt_offset(b, n) \
435 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
437 #define sector(s) ((s) & 0x3f)
439 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
441 #define hsc2sector(h,s,c) \
442 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
447 /* Not really closing, but making sure it is open, and to harmless place */
448 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
452 * Return partition name - uses static storage
455 partname(const char *dev, int pno, int lth)
462 bufp = partname_buffer;
463 bufsiz = sizeof(partname_buffer);
468 if (isdigit(dev[w-1]))
471 /* devfs kludge - note: fdisk partition names are not supposed
472 to equal kernel names, so there is no reason to do this */
473 if (strcmp(dev + w - 4, "disc") == 0) {
481 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
482 lth-wp-2, w, dev, p, pno);
484 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
489 static ALWAYS_INLINE struct partition *
490 get_part_table(int i)
492 return ptes[i].part_table;
497 { /* n==1: use singular */
499 return display_in_cyl_units ? "cylinder" : "sector";
500 return display_in_cyl_units ? "cylinders" : "sectors";
504 valid_part_table_flag(const char *mbuffer)
506 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
509 static void fdisk_fatal(const char *why)
513 longjmp(listingbuf, 1);
515 bb_error_msg_and_die(why, disk_device);
519 seek_sector(sector_t secno)
521 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
522 off64_t off = (off64_t)secno * sector_size;
523 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
524 fdisk_fatal(unable_to_seek);
526 uint64_t off = (uint64_t)secno * sector_size;
527 if (off > MAXINT(off_t)
528 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
530 fdisk_fatal(unable_to_seek);
535 #if ENABLE_FEATURE_FDISK_WRITABLE
536 /* Read line; return 0 or first printable char */
538 read_line(const char *prompt)
542 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
544 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
546 if (line_buffer[sz-1] == '\n')
547 line_buffer[--sz] = '\0';
549 line_ptr = line_buffer;
550 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
556 set_all_unchanged(void)
560 for (i = 0; i < MAXIMUM_PARTS; i++)
564 static ALWAYS_INLINE void
570 static ALWAYS_INLINE void
571 write_part_table_flag(char *b)
578 read_nonempty(const char *mesg)
580 while (!read_line(mesg))
586 read_maybe_empty(const char *mesg)
588 if (!read_line(mesg)) {
589 line_ptr = line_buffer;
597 read_hex(const char *const *sys)
601 read_nonempty("Hex code (type L to list codes): ");
602 if ((line_ptr[0] | 0x20) == 'l') {
606 v = bb_strtoul(line_ptr, NULL, 16);
613 write_sector(sector_t secno, const void *buf)
616 xwrite(dev_fd, buf, sector_size);
618 #endif /* FEATURE_FDISK_WRITABLE */
621 #include "fdisk_aix.c"
623 struct sun_partition {
624 unsigned char info[128]; /* Informative text string */
625 unsigned char spare0[14];
627 unsigned char spare1;
629 unsigned char spare2;
632 unsigned char spare1[246]; /* Boot information etc. */
633 unsigned short rspeed; /* Disk rotational speed */
634 unsigned short pcylcount; /* Physical cylinder count */
635 unsigned short sparecyl; /* extra sects per cylinder */
636 unsigned char spare2[4]; /* More magic... */
637 unsigned short ilfact; /* Interleave factor */
638 unsigned short ncyl; /* Data cylinder count */
639 unsigned short nacyl; /* Alt. cylinder count */
640 unsigned short ntrks; /* Tracks per cylinder */
641 unsigned short nsect; /* Sectors per track */
642 unsigned char spare3[4]; /* Even more magic... */
643 struct sun_partinfo {
644 uint32_t start_cylinder;
645 uint32_t num_sectors;
647 unsigned short magic; /* Magic number */
648 unsigned short csum; /* Label xor'd checksum */
650 typedef struct sun_partition sun_partition;
651 #define sunlabel ((sun_partition *)MBRbuffer)
652 STATIC_OSF void bsd_select(void);
653 STATIC_OSF void xbsd_print_disklabel(int);
654 #include "fdisk_osf.c"
656 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
658 fdisk_swap16(uint16_t x)
660 return (x << 8) | (x >> 8);
664 fdisk_swap32(uint32_t x)
667 ((x & 0xFF00) << 8) |
668 ((x & 0xFF0000) >> 8) |
673 STATIC_SGI const char *const sgi_sys_types[];
674 STATIC_SGI unsigned sgi_get_num_sectors(int i);
675 STATIC_SGI int sgi_get_sysid(int i);
676 STATIC_SGI void sgi_delete_partition(int i);
677 STATIC_SGI void sgi_change_sysid(int i, int sys);
678 STATIC_SGI void sgi_list_table(int xtra);
679 #if ENABLE_FEATURE_FDISK_ADVANCED
680 STATIC_SGI void sgi_set_xcyl(void);
682 STATIC_SGI int verify_sgi(int verbose);
683 STATIC_SGI void sgi_add_partition(int n, int sys);
684 STATIC_SGI void sgi_set_swappartition(int i);
685 STATIC_SGI const char *sgi_get_bootfile(void);
686 STATIC_SGI void sgi_set_bootfile(const char* aFile);
687 STATIC_SGI void create_sgiinfo(void);
688 STATIC_SGI void sgi_write_table(void);
689 STATIC_SGI void sgi_set_bootpartition(int i);
690 #include "fdisk_sgi.c"
692 STATIC_SUN const char *const sun_sys_types[];
693 STATIC_SUN void sun_delete_partition(int i);
694 STATIC_SUN void sun_change_sysid(int i, int sys);
695 STATIC_SUN void sun_list_table(int xtra);
696 STATIC_SUN void add_sun_partition(int n, int sys);
697 #if ENABLE_FEATURE_FDISK_ADVANCED
698 STATIC_SUN void sun_set_alt_cyl(void);
699 STATIC_SUN void sun_set_ncyl(int cyl);
700 STATIC_SUN void sun_set_xcyl(void);
701 STATIC_SUN void sun_set_ilfact(void);
702 STATIC_SUN void sun_set_rspeed(void);
703 STATIC_SUN void sun_set_pcylcount(void);
705 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
706 STATIC_SUN void verify_sun(void);
707 STATIC_SUN void sun_write_table(void);
708 #include "fdisk_sun.c"
711 static inline_if_little_endian unsigned
712 read4_little_endian(const unsigned char *cp)
715 move_from_unaligned32(v, cp);
720 get_start_sect(const struct partition *p)
722 return read4_little_endian(p->start4);
726 get_nr_sects(const struct partition *p)
728 return read4_little_endian(p->size4);
731 #if ENABLE_FEATURE_FDISK_WRITABLE
732 /* start_sect and nr_sects are stored little endian on all machines */
733 /* moreover, they are not aligned correctly */
734 static inline_if_little_endian void
735 store4_little_endian(unsigned char *cp, unsigned val)
737 uint32_t v = SWAP_LE32(val);
738 move_to_unaligned32(cp, v);
742 set_start_sect(struct partition *p, unsigned start_sect)
744 store4_little_endian(p->start4, start_sect);
748 set_nr_sects(struct partition *p, unsigned nr_sects)
750 store4_little_endian(p->size4, nr_sects);
754 /* Allocate a buffer and read a partition table sector */
756 read_pte(struct pte *pe, sector_t offset)
758 pe->offset_from_dev_start = offset;
759 pe->sectorbuffer = xzalloc(sector_size);
761 /* xread would make us abort - bad for fdisk -l */
762 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
763 fdisk_fatal(unable_to_read);
764 #if ENABLE_FEATURE_FDISK_WRITABLE
767 pe->part_table = pe->ext_pointer = NULL;
771 get_partition_start_from_dev_start(const struct pte *pe)
773 return pe->offset_from_dev_start + get_start_sect(pe->part_table);
776 #if ENABLE_FEATURE_FDISK_WRITABLE
778 * Avoid warning about DOS partitions when no DOS partition was changed.
779 * Here a heuristic "is probably dos partition".
780 * We might also do the opposite and warn in all cases except
781 * for "is probably nondos partition".
785 is_dos_partition(int t)
787 return (t == 1 || t == 4 || t == 6 ||
788 t == 0x0b || t == 0x0c || t == 0x0e ||
789 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
790 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
791 t == 0xc1 || t == 0xc4 || t == 0xc6);
798 puts("Command Action");
800 puts("a\ttoggle a read only flag"); /* sun */
801 puts("b\tedit bsd disklabel");
802 puts("c\ttoggle the mountable flag"); /* sun */
803 puts("d\tdelete a partition");
804 puts("l\tlist known partition types");
805 puts("n\tadd a new partition");
806 puts("o\tcreate a new empty DOS partition table");
807 puts("p\tprint the partition table");
808 puts("q\tquit without saving changes");
809 puts("s\tcreate a new empty Sun disklabel"); /* sun */
810 puts("t\tchange a partition's system id");
811 puts("u\tchange display/entry units");
812 puts("v\tverify the partition table");
813 puts("w\twrite table to disk and exit");
814 #if ENABLE_FEATURE_FDISK_ADVANCED
815 puts("x\textra functionality (experts only)");
817 } else if (LABEL_IS_SGI) {
818 puts("a\tselect bootable partition"); /* sgi flavour */
819 puts("b\tedit bootfile entry"); /* sgi */
820 puts("c\tselect sgi swap partition"); /* sgi flavour */
821 puts("d\tdelete a partition");
822 puts("l\tlist known partition types");
823 puts("n\tadd a new partition");
824 puts("o\tcreate a new empty DOS partition table");
825 puts("p\tprint the partition table");
826 puts("q\tquit without saving changes");
827 puts("s\tcreate a new empty Sun disklabel"); /* sun */
828 puts("t\tchange a partition's system id");
829 puts("u\tchange display/entry units");
830 puts("v\tverify the partition table");
831 puts("w\twrite table to disk and exit");
832 } else if (LABEL_IS_AIX) {
833 puts("o\tcreate a new empty DOS partition table");
834 puts("q\tquit without saving changes");
835 puts("s\tcreate a new empty Sun disklabel"); /* sun */
837 puts("a\ttoggle a bootable flag");
838 puts("b\tedit bsd disklabel");
839 puts("c\ttoggle the dos compatibility flag");
840 puts("d\tdelete a partition");
841 puts("l\tlist known partition types");
842 puts("n\tadd a new partition");
843 puts("o\tcreate a new empty DOS partition table");
844 puts("p\tprint the partition table");
845 puts("q\tquit without saving changes");
846 puts("s\tcreate a new empty Sun disklabel"); /* sun */
847 puts("t\tchange a partition's system id");
848 puts("u\tchange display/entry units");
849 puts("v\tverify the partition table");
850 puts("w\twrite table to disk and exit");
851 #if ENABLE_FEATURE_FDISK_ADVANCED
852 puts("x\textra functionality (experts only)");
856 #endif /* FEATURE_FDISK_WRITABLE */
859 #if ENABLE_FEATURE_FDISK_ADVANCED
863 puts("Command Action");
865 puts("a\tchange number of alternate cylinders"); /*sun*/
866 puts("c\tchange number of cylinders");
867 puts("d\tprint the raw data in the partition table");
868 puts("e\tchange number of extra sectors per cylinder");/*sun*/
869 puts("h\tchange number of heads");
870 puts("i\tchange interleave factor"); /*sun*/
871 puts("o\tchange rotation speed (rpm)"); /*sun*/
872 puts("p\tprint the partition table");
873 puts("q\tquit without saving changes");
874 puts("r\treturn to main menu");
875 puts("s\tchange number of sectors/track");
876 puts("v\tverify the partition table");
877 puts("w\twrite table to disk and exit");
878 puts("y\tchange number of physical cylinders"); /*sun*/
879 } else if (LABEL_IS_SGI) {
880 puts("b\tmove beginning of data in a partition"); /* !sun */
881 puts("c\tchange number of cylinders");
882 puts("d\tprint the raw data in the partition table");
883 puts("e\tlist extended partitions"); /* !sun */
884 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
885 puts("h\tchange number of heads");
886 puts("p\tprint the partition table");
887 puts("q\tquit without saving changes");
888 puts("r\treturn to main menu");
889 puts("s\tchange number of sectors/track");
890 puts("v\tverify the partition table");
891 puts("w\twrite table to disk and exit");
892 } else if (LABEL_IS_AIX) {
893 puts("b\tmove beginning of data in a partition"); /* !sun */
894 puts("c\tchange number of cylinders");
895 puts("d\tprint the raw data in the partition table");
896 puts("e\tlist extended partitions"); /* !sun */
897 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
898 puts("h\tchange number of heads");
899 puts("p\tprint the partition table");
900 puts("q\tquit without saving changes");
901 puts("r\treturn to main menu");
902 puts("s\tchange number of sectors/track");
903 puts("v\tverify the partition table");
904 puts("w\twrite table to disk and exit");
906 puts("b\tmove beginning of data in a partition"); /* !sun */
907 puts("c\tchange number of cylinders");
908 puts("d\tprint the raw data in the partition table");
909 puts("e\tlist extended partitions"); /* !sun */
910 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
911 #if ENABLE_FEATURE_SGI_LABEL
912 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
914 puts("h\tchange number of heads");
915 puts("p\tprint the partition table");
916 puts("q\tquit without saving changes");
917 puts("r\treturn to main menu");
918 puts("s\tchange number of sectors/track");
919 puts("v\tverify the partition table");
920 puts("w\twrite table to disk and exit");
923 #endif /* ADVANCED mode */
925 #if ENABLE_FEATURE_FDISK_WRITABLE
926 static const char *const *
930 LABEL_IS_SUN ? sun_sys_types :
931 LABEL_IS_SGI ? sgi_sys_types :
935 #define get_sys_types() i386_sys_types
939 partition_type(unsigned char type)
942 const char *const *types = get_sys_types();
944 for (i = 0; types[i]; i++)
945 if ((unsigned char)types[i][0] == type)
952 is_cleared_partition(const struct partition *p)
954 /* We consider partition "cleared" only if it has only zeros */
955 const char *cp = (const char *)p;
956 int cnt = sizeof(*p);
964 clear_partition(struct partition *p)
967 memset(p, 0, sizeof(*p));
970 #if ENABLE_FEATURE_FDISK_WRITABLE
974 return LABEL_IS_SUN ? sunlabel->infos[i].id :
975 (LABEL_IS_SGI ? sgi_get_sysid(i) :
976 ptes[i].part_table->sys_ind);
980 list_types(const char *const *sys)
985 unsigned done, next, size;
988 for (size = 0; sys[size]; size++)
992 for (i = COLS-1; i >= 0; i--) {
993 done += (size + i - done) / (i + 1);
994 last[COLS-1 - i] = done;
999 printf("%c%2x %-22.22s", i ? ' ' : '\n',
1000 (unsigned char)sys[next][0],
1002 next = last[i++] + done;
1003 if (i >= COLS || next >= last[i]) {
1007 } while (done < last[0]);
1011 #define set_hsc(h, s, c, sector) do \
1013 s = sector % g_sectors + 1; \
1014 sector /= g_sectors; \
1015 h = sector % g_heads; \
1016 sector /= g_heads; \
1017 c = sector & 0xff; \
1018 s |= (sector >> 2) & 0xc0; \
1021 static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop)
1023 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1024 start = g_heads * g_sectors * 1024 - 1;
1025 set_hsc(p->head, p->sector, p->cyl, start);
1027 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1028 stop = g_heads * g_sectors * 1024 - 1;
1029 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1033 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1035 struct partition *p;
1039 p = ptes[i].ext_pointer;
1040 offset = extended_offset;
1042 p = ptes[i].part_table;
1043 offset = ptes[i].offset_from_dev_start;
1047 set_start_sect(p, start - offset);
1048 set_nr_sects(p, stop - start + 1);
1049 set_hsc_start_end(p, start, stop);
1050 ptes[i].changed = 1;
1057 if (g_heads && g_sectors && g_cylinders)
1060 printf("Unknown value(s) for:");
1066 printf(" cylinders");
1068 #if ENABLE_FEATURE_FDISK_WRITABLE
1069 " (settable in the extra functions menu)"
1078 int cyl_units = g_heads * g_sectors;
1080 if (display_in_cyl_units && cyl_units)
1081 units_per_sector = cyl_units;
1083 units_per_sector = 1; /* in sectors */
1086 #if ENABLE_FEATURE_FDISK_WRITABLE
1088 warn_cylinders(void)
1090 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1092 "The number of cylinders for this disk is set to %u.\n"
1093 "There is nothing wrong with that, but this is larger than 1024,\n"
1094 "and could in certain setups cause problems with:\n"
1095 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1096 "2) booting and partitioning software from other OSs\n"
1097 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1103 read_extended(int ext)
1107 struct partition *p, *q;
1111 pex->ext_pointer = pex->part_table;
1113 p = pex->part_table;
1114 if (!get_start_sect(p)) {
1115 printf("Bad offset in primary extended partition\n");
1119 while (IS_EXTENDED(p->sys_ind)) {
1120 struct pte *pe = &ptes[g_partitions];
1122 if (g_partitions >= MAXIMUM_PARTS) {
1123 /* This is not a Linux restriction, but
1124 this program uses arrays of size MAXIMUM_PARTS.
1125 Do not try to 'improve' this test. */
1126 struct pte *pre = &ptes[g_partitions - 1];
1127 #if ENABLE_FEATURE_FDISK_WRITABLE
1128 printf("Warning: deleting partitions after %u\n",
1132 clear_partition(pre->ext_pointer);
1136 read_pte(pe, extended_offset + get_start_sect(p));
1138 if (!extended_offset)
1139 extended_offset = get_start_sect(p);
1141 q = p = pt_offset(pe->sectorbuffer, 0);
1142 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1143 if (IS_EXTENDED(p->sys_ind)) {
1144 if (pe->ext_pointer)
1145 printf("Warning: extra link "
1146 "pointer in partition table"
1147 " %u\n", g_partitions + 1);
1149 pe->ext_pointer = p;
1150 } else if (p->sys_ind) {
1152 printf("Warning: ignoring extra "
1153 "data in partition table"
1154 " %u\n", g_partitions + 1);
1160 /* very strange code here... */
1161 if (!pe->part_table) {
1162 if (q != pe->ext_pointer)
1165 pe->part_table = q + 1;
1167 if (!pe->ext_pointer) {
1168 if (q != pe->part_table)
1169 pe->ext_pointer = q;
1171 pe->ext_pointer = q + 1;
1174 p = pe->ext_pointer;
1178 #if ENABLE_FEATURE_FDISK_WRITABLE
1179 /* remove empty links */
1181 for (i = 4; i < g_partitions; i++) {
1182 struct pte *pe = &ptes[i];
1184 if (!get_nr_sects(pe->part_table)
1185 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1187 printf("Omitting empty partition (%u)\n", i+1);
1188 delete_partition(i);
1189 goto remove; /* numbering changed */
1195 #if ENABLE_FEATURE_FDISK_WRITABLE
1197 create_doslabel(void)
1199 printf(msg_building_new_label, "DOS disklabel");
1201 current_label_type = LABEL_DOS;
1202 #if ENABLE_FEATURE_OSF_LABEL
1203 possibly_osf_label = 0;
1207 memset(&MBRbuffer[510 - 4*16], 0, 4*16);
1208 write_part_table_flag(MBRbuffer);
1209 extended_offset = 0;
1210 set_all_unchanged();
1212 get_boot(CREATE_EMPTY_DOS);
1217 get_sectorsize(void)
1219 if (!user_set_sector_size) {
1221 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1223 if (sector_size != DEFAULT_SECTOR_SIZE)
1224 printf("Note: sector size is %u "
1225 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1231 get_kernel_geometry(void)
1233 struct hd_geometry geometry;
1235 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1236 kern_heads = geometry.heads;
1237 kern_sectors = geometry.sectors;
1238 /* never use geometry.cylinders - it is truncated */
1243 get_partition_table_geometry(void)
1245 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1246 struct partition *p;
1247 int i, h, s, hh, ss;
1251 if (!(valid_part_table_flag((char*)bufp)))
1255 for (i = 0; i < 4; i++) {
1256 p = pt_offset(bufp, i);
1257 if (p->sys_ind != 0) {
1258 h = p->end_head + 1;
1259 s = (p->end_sector & 077);
1264 } else if (hh != h || ss != s)
1269 if (!first && !bad) {
1281 sec_fac = sector_size / 512;
1282 #if ENABLE_FEATURE_SUN_LABEL
1283 guess_device_type();
1285 g_heads = g_cylinders = g_sectors = 0;
1286 kern_heads = kern_sectors = 0;
1287 pt_heads = pt_sectors = 0;
1289 get_kernel_geometry();
1290 get_partition_table_geometry();
1292 g_heads = user_heads ? user_heads :
1293 pt_heads ? pt_heads :
1294 kern_heads ? kern_heads : 255;
1295 g_sectors = user_sectors ? user_sectors :
1296 pt_sectors ? pt_sectors :
1297 kern_sectors ? kern_sectors : 63;
1298 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1301 if (dos_compatible_flag)
1302 sector_offset = g_sectors;
1304 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1306 g_cylinders = user_cylinders;
1310 * Opens disk_device and optionally reads MBR.
1311 * FIXME: document what each 'what' value will do!
1313 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1314 * 0: found or created label
1317 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1318 static int get_boot(enum action what)
1320 static int get_boot(void)
1321 #define get_boot(what) get_boot()
1327 for (i = 0; i < 4; i++) {
1328 struct pte *pe = &ptes[i];
1329 pe->part_table = pt_offset(MBRbuffer, i);
1330 pe->ext_pointer = NULL;
1331 pe->offset_from_dev_start = 0;
1332 pe->sectorbuffer = MBRbuffer;
1333 #if ENABLE_FEATURE_FDISK_WRITABLE
1334 pe->changed = (what == CREATE_EMPTY_DOS);
1338 #if ENABLE_FEATURE_FDISK_WRITABLE
1339 // ALERT! highly idiotic design!
1340 // We end up here when we call get_boot() recursively
1341 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1342 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1343 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1344 // So skip opening device _again_...
1345 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1348 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1351 fd = open(disk_device, O_RDONLY);
1353 if (what == TRY_ONLY)
1355 fdisk_fatal(unable_to_open);
1357 printf("'%s' is opened for read only\n", disk_device);
1359 xmove_fd(fd, dev_fd);
1360 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1361 if (what == TRY_ONLY) {
1365 fdisk_fatal(unable_to_read);
1368 fd = open(disk_device, O_RDONLY);
1371 if (512 != full_read(fd, MBRbuffer, 512)) {
1375 xmove_fd(fd, dev_fd);
1381 #if ENABLE_FEATURE_SUN_LABEL
1382 if (check_sun_label())
1385 #if ENABLE_FEATURE_SGI_LABEL
1386 if (check_sgi_label())
1389 #if ENABLE_FEATURE_AIX_LABEL
1390 if (check_aix_label())
1393 #if ENABLE_FEATURE_OSF_LABEL
1394 if (check_osf_label()) {
1395 possibly_osf_label = 1;
1396 if (!valid_part_table_flag(MBRbuffer)) {
1397 current_label_type = LABEL_OSF;
1400 printf("This disk has both DOS and BSD magic.\n"
1401 "Give the 'b' command to go to BSD mode.\n");
1405 #if !ENABLE_FEATURE_FDISK_WRITABLE
1406 if (!valid_part_table_flag(MBRbuffer))
1409 if (!valid_part_table_flag(MBRbuffer)) {
1410 if (what == OPEN_MAIN) {
1411 printf("Device contains neither a valid DOS "
1412 "partition table, nor Sun, SGI or OSF "
1415 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1425 #endif /* FEATURE_FDISK_WRITABLE */
1428 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1431 for (i = 0; i < 4; i++) {
1432 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1433 if (g_partitions != 4)
1434 printf("Ignoring extra extended "
1435 "partition %u\n", i + 1);
1441 for (i = 3; i < g_partitions; i++) {
1442 struct pte *pe = &ptes[i];
1443 if (!valid_part_table_flag(pe->sectorbuffer)) {
1444 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1445 "table %u will be corrected by w(rite)\n",
1446 pe->sectorbuffer[510],
1447 pe->sectorbuffer[511],
1449 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1456 #if ENABLE_FEATURE_FDISK_WRITABLE
1458 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1459 * If the user hits Enter, DFLT is returned.
1460 * Answers like +10 are interpreted as offsets from BASE.
1462 * There is no default if DFLT is not between LOW and HIGH.
1465 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1469 const char *fmt = "%s (%u-%u, default %u): ";
1471 if (dflt < low || dflt > high) {
1472 fmt = "%s (%u-%u): ";
1477 int use_default = default_ok;
1479 /* ask question and read answer */
1481 printf(fmt, mesg, low, high, dflt);
1482 read_maybe_empty("");
1483 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1484 && *line_ptr != '-' && *line_ptr != '+');
1486 if (*line_ptr == '+' || *line_ptr == '-') {
1487 int minus = (*line_ptr == '-');
1490 value = atoi(line_ptr + 1);
1492 /* (1) if 2nd char is digit, use_default = 0.
1493 * (2) move line_ptr to first non-digit. */
1494 while (isdigit(*++line_ptr))
1497 switch (*line_ptr) {
1500 if (!display_in_cyl_units)
1501 value *= g_heads * g_sectors;
1515 absolute = 1000000000;
1524 bytes = (ullong) value * absolute;
1525 unit = sector_size * units_per_sector;
1526 bytes += unit/2; /* round */
1534 value = atoi(line_ptr);
1535 while (isdigit(*line_ptr)) {
1542 printf("Using default value %u\n", value);
1544 if (value >= low && value <= high)
1546 printf("Value is out of range\n");
1552 get_partition(int warn, unsigned max)
1557 i = read_int(1, 0, max, 0, "Partition number") - 1;
1561 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1562 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1563 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1565 printf("Warning: partition %u has empty type\n", i+1);
1572 get_existing_partition(int warn, unsigned max)
1577 for (i = 0; i < max; i++) {
1578 struct pte *pe = &ptes[i];
1579 struct partition *p = pe->part_table;
1581 if (p && !is_cleared_partition(p)) {
1588 printf("Selected partition %u\n", pno+1);
1591 printf("No partition is defined yet!\n");
1595 return get_partition(warn, max);
1599 get_nonexisting_partition(int warn, unsigned max)
1604 for (i = 0; i < max; i++) {
1605 struct pte *pe = &ptes[i];
1606 struct partition *p = pe->part_table;
1608 if (p && is_cleared_partition(p)) {
1615 printf("Selected partition %u\n", pno+1);
1618 printf("All primary partitions have been defined already!\n");
1622 return get_partition(warn, max);
1629 display_in_cyl_units = !display_in_cyl_units;
1631 printf("Changing display/entry units to %s\n",
1636 toggle_active(int i)
1638 struct pte *pe = &ptes[i];
1639 struct partition *p = pe->part_table;
1641 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1642 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1643 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1648 toggle_dos_compatibility_flag(void)
1650 dos_compatible_flag = 1 - dos_compatible_flag;
1651 if (dos_compatible_flag) {
1652 sector_offset = g_sectors;
1653 printf("DOS Compatibility flag is set\n");
1656 printf("DOS Compatibility flag is not set\n");
1661 delete_partition(int i)
1663 struct pte *pe = &ptes[i];
1664 struct partition *p = pe->part_table;
1665 struct partition *q = pe->ext_pointer;
1667 /* Note that for the fifth partition (i == 4) we don't actually
1668 * decrement partitions.
1671 if (warn_geometry())
1672 return; /* C/H/S not set */
1676 sun_delete_partition(i);
1680 sgi_delete_partition(i);
1685 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1687 ptes[ext_index].ext_pointer = NULL;
1688 extended_offset = 0;
1694 if (!q->sys_ind && i > 4) {
1695 /* the last one in the chain - just delete */
1698 clear_partition(ptes[i].ext_pointer);
1699 ptes[i].changed = 1;
1701 /* not the last one - further ones will be moved down */
1703 /* delete this link in the chain */
1704 p = ptes[i-1].ext_pointer;
1706 set_start_sect(p, get_start_sect(q));
1707 set_nr_sects(p, get_nr_sects(q));
1708 ptes[i-1].changed = 1;
1709 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1710 /* the first logical in a longer chain */
1713 if (pe->part_table) /* prevent SEGFAULT */
1714 set_start_sect(pe->part_table,
1715 get_partition_start_from_dev_start(pe) -
1717 pe->offset_from_dev_start = extended_offset;
1721 if (g_partitions > 5) {
1723 while (i < g_partitions) {
1724 ptes[i] = ptes[i+1];
1728 /* the only logical: clear only */
1729 clear_partition(ptes[i].part_table);
1737 int i, sys, origsys;
1738 struct partition *p;
1740 /* If sgi_label then don't use get_existing_partition,
1741 let the user select a partition, since get_existing_partition()
1742 only works for Linux like partition tables. */
1743 if (!LABEL_IS_SGI) {
1744 i = get_existing_partition(0, g_partitions);
1746 i = get_partition(0, g_partitions);
1750 p = ptes[i].part_table;
1751 origsys = sys = get_sysid(i);
1753 /* if changing types T to 0 is allowed, then
1754 the reverse change must be allowed, too */
1755 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1756 printf("Partition %u does not exist yet!\n", i + 1);
1760 sys = read_hex(get_sys_types());
1762 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1763 printf("Type 0 means free space to many systems\n"
1764 "(but not to Linux). Having partitions of\n"
1765 "type 0 is probably unwise.\n");
1769 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1770 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1771 printf("You cannot change a partition into"
1772 " an extended one or vice versa\n");
1778 #if ENABLE_FEATURE_SUN_LABEL
1779 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1780 printf("Consider leaving partition 3 "
1781 "as Whole disk (5),\n"
1782 "as SunOS/Solaris expects it and "
1783 "even Linux likes it\n\n");
1785 #if ENABLE_FEATURE_SGI_LABEL
1788 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1789 (i == 8 && sys != 0)
1792 printf("Consider leaving partition 9 "
1793 "as volume header (0),\nand "
1794 "partition 11 as entire volume (6)"
1795 "as IRIX expects it\n\n");
1801 sun_change_sysid(i, sys);
1802 } else if (LABEL_IS_SGI) {
1803 sgi_change_sysid(i, sys);
1807 printf("Changed system type of partition %u "
1808 "to %x (%s)\n", i + 1, sys,
1809 partition_type(sys));
1810 ptes[i].changed = 1;
1811 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1817 #endif /* FEATURE_FDISK_WRITABLE */
1820 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1821 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1822 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1823 * Lubkin Oct. 1991). */
1826 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1828 int spc = g_heads * g_sectors;
1832 *h = ls / g_sectors;
1833 *s = ls % g_sectors + 1; /* sectors count from 1 */
1837 check_consistency(const struct partition *p, int partition)
1839 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1840 unsigned pec, peh, pes; /* physical ending c, h, s */
1841 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1842 unsigned lec, leh, les; /* logical ending c, h, s */
1844 if (!g_heads || !g_sectors || (partition >= 4))
1845 return; /* do not check extended partitions */
1847 /* physical beginning c, h, s */
1848 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1850 pbs = p->sector & 0x3f;
1852 /* physical ending c, h, s */
1853 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1855 pes = p->end_sector & 0x3f;
1857 /* compute logical beginning (c, h, s) */
1858 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1860 /* compute logical ending (c, h, s) */
1861 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1863 /* Same physical / logical beginning? */
1864 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1865 printf("Partition %u has different physical/logical "
1866 "beginnings (non-Linux?):\n", partition + 1);
1867 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
1868 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
1871 /* Same physical / logical ending? */
1872 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1873 printf("Partition %u has different physical/logical "
1874 "endings:\n", partition + 1);
1875 printf(" phys=(%u, %u, %u) ", pec, peh, pes);
1876 printf("logical=(%u, %u, %u)\n", lec, leh, les);
1879 /* Ending on cylinder boundary? */
1880 if (peh != (g_heads - 1) || pes != g_sectors) {
1881 printf("Partition %u does not end on cylinder boundary\n",
1887 list_disk_geometry(void)
1889 ullong bytes = ((ullong)total_number_of_sectors << 9);
1890 long megabytes = bytes / 1000000;
1892 if (megabytes < 10000)
1893 printf("\nDisk %s: %lu MB, %llu bytes\n",
1894 disk_device, megabytes, bytes);
1896 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1897 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1898 printf("%u heads, %u sectors/track, %u cylinders",
1899 g_heads, g_sectors, g_cylinders);
1900 if (units_per_sector == 1)
1901 printf(", total %"SECT_FMT"u sectors",
1902 total_number_of_sectors / (sector_size/512));
1903 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1905 units_per_sector, sector_size, units_per_sector * sector_size);
1909 * Check whether partition entries are ordered by their starting positions.
1910 * Return 0 if OK. Return i if partition i should have been earlier.
1911 * Two separate checks: primary and logical partitions.
1914 wrong_p_order(int *prev)
1916 const struct pte *pe;
1917 const struct partition *p;
1918 sector_t last_p_start_pos = 0, p_start_pos;
1919 unsigned i, last_i = 0;
1921 for (i = 0; i < g_partitions; i++) {
1924 last_p_start_pos = 0;
1929 p_start_pos = get_partition_start_from_dev_start(pe);
1931 if (last_p_start_pos > p_start_pos) {
1937 last_p_start_pos = p_start_pos;
1944 #if ENABLE_FEATURE_FDISK_ADVANCED
1946 * Fix the chain of logicals.
1947 * extended_offset is unchanged, the set of sectors used is unchanged
1948 * The chain is sorted so that sectors increase, and so that
1949 * starting sectors increase.
1951 * After this it may still be that cfdisk doesnt like the table.
1952 * (This is because cfdisk considers expanded parts, from link to
1953 * end of partition, and these may still overlap.)
1955 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1959 fix_chain_of_logicals(void)
1961 int j, oj, ojj, sj, sjj;
1962 struct partition *pj,*pjj,tmp;
1964 /* Stage 1: sort sectors but leave sector of part 4 */
1965 /* (Its sector is the global extended_offset.) */
1967 for (j = 5; j < g_partitions - 1; j++) {
1968 oj = ptes[j].offset_from_dev_start;
1969 ojj = ptes[j+1].offset_from_dev_start;
1971 ptes[j].offset_from_dev_start = ojj;
1972 ptes[j+1].offset_from_dev_start = oj;
1973 pj = ptes[j].part_table;
1974 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1975 pjj = ptes[j+1].part_table;
1976 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1977 set_start_sect(ptes[j-1].ext_pointer,
1978 ojj-extended_offset);
1979 set_start_sect(ptes[j].ext_pointer,
1980 oj-extended_offset);
1985 /* Stage 2: sort starting sectors */
1987 for (j = 4; j < g_partitions - 1; j++) {
1988 pj = ptes[j].part_table;
1989 pjj = ptes[j+1].part_table;
1990 sj = get_start_sect(pj);
1991 sjj = get_start_sect(pjj);
1992 oj = ptes[j].offset_from_dev_start;
1993 ojj = ptes[j+1].offset_from_dev_start;
1994 if (oj+sj > ojj+sjj) {
1998 set_start_sect(pj, ojj+sjj-oj);
1999 set_start_sect(pjj, oj+sj-ojj);
2004 /* Probably something was changed */
2005 for (j = 4; j < g_partitions; j++)
2006 ptes[j].changed = 1;
2011 fix_partition_table_order(void)
2013 struct pte *pei, *pek;
2016 if (!wrong_p_order(NULL)) {
2017 printf("Ordering is already correct\n\n");
2021 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2022 /* partition i should have come earlier, move it */
2023 /* We have to move data in the MBR */
2024 struct partition *pi, *pk, *pe, pbuf;
2028 pe = pei->ext_pointer;
2029 pei->ext_pointer = pek->ext_pointer;
2030 pek->ext_pointer = pe;
2032 pi = pei->part_table;
2033 pk = pek->part_table;
2035 memmove(&pbuf, pi, sizeof(struct partition));
2036 memmove(pi, pk, sizeof(struct partition));
2037 memmove(pk, &pbuf, sizeof(struct partition));
2039 pei->changed = pek->changed = 1;
2043 fix_chain_of_logicals();
2051 list_table(int xtra)
2053 const struct partition *p;
2057 sun_list_table(xtra);
2061 sgi_list_table(xtra);
2065 list_disk_geometry();
2068 xbsd_print_disklabel(xtra);
2072 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2073 but if the device name ends in a digit, say /dev/foo1,
2074 then the partition is called /dev/foo1p3. */
2075 w = strlen(disk_device);
2076 if (w && isdigit(disk_device[w-1]))
2081 // 1 12345678901 12345678901 12345678901 12
2082 printf("%*s Boot Start End Blocks Id System\n",
2085 for (i = 0; i < g_partitions; i++) {
2086 const struct pte *pe = &ptes[i];
2092 if (!p || is_cleared_partition(p))
2095 psects = get_nr_sects(p);
2099 if (sector_size < 1024) {
2100 pblocks /= (1024 / sector_size);
2101 podd = psects % (1024 / sector_size);
2103 if (sector_size > 1024)
2104 pblocks *= (sector_size / 1024);
2106 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
2107 partname(disk_device, i+1, w+2),
2108 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2110 cround(get_partition_start_from_dev_start(pe)), /* start */
2111 cround(get_partition_start_from_dev_start(pe) + psects /* end */
2112 - (psects ? 1 : 0)),
2113 pblocks, podd ? '+' : ' ', /* odd flag on end */
2114 p->sys_ind, /* type id */
2115 partition_type(p->sys_ind)); /* type name */
2117 check_consistency(p, i);
2120 /* Is partition table in disk order? It need not be, but... */
2121 /* partition table entries are not checked for correct order
2122 * if this is a sgi, sun or aix labeled disk... */
2123 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2125 printf("\nPartition table entries are not in disk order\n");
2129 #if ENABLE_FEATURE_FDISK_ADVANCED
2131 x_list_table(int extend)
2133 const struct pte *pe;
2134 const struct partition *p;
2137 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2138 disk_device, g_heads, g_sectors, g_cylinders);
2139 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2140 for (i = 0; i < g_partitions; i++) {
2142 p = (extend ? pe->ext_pointer : pe->part_table);
2144 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2145 i + 1, p->boot_ind, p->head,
2147 cylinder(p->sector, p->cyl), p->end_head,
2148 sector(p->end_sector),
2149 cylinder(p->end_sector, p->end_cyl),
2150 get_start_sect(p), get_nr_sects(p),
2153 check_consistency(p, i);
2159 #if ENABLE_FEATURE_FDISK_WRITABLE
2161 fill_bounds(sector_t *first, sector_t *last)
2164 const struct pte *pe = &ptes[0];
2165 const struct partition *p;
2167 for (i = 0; i < g_partitions; pe++,i++) {
2169 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2170 first[i] = 0xffffffff;
2173 first[i] = get_partition_start_from_dev_start(pe);
2174 last[i] = first[i] + get_nr_sects(p) - 1;
2180 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2182 sector_t total, real_s, real_c;
2184 real_s = sector(s) - 1;
2185 real_c = cylinder(s, c);
2186 total = (real_c * g_sectors + real_s) * g_heads + h;
2188 printf("Partition %u contains sector 0\n", n);
2190 printf("Partition %u: head %u greater than maximum %u\n",
2192 if (real_s >= g_sectors)
2193 printf("Partition %u: sector %u greater than "
2194 "maximum %u\n", n, s, g_sectors);
2195 if (real_c >= g_cylinders)
2196 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2197 "maximum %u\n", n, real_c + 1, g_cylinders);
2198 if (g_cylinders <= 1024 && start != total)
2199 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2200 "total %"SECT_FMT"u\n", n, start, total);
2208 sector_t first[g_partitions], last[g_partitions];
2209 struct partition *p;
2211 if (warn_geometry())
2223 fill_bounds(first, last);
2224 for (i = 0; i < g_partitions; i++) {
2225 struct pte *pe = &ptes[i];
2228 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2229 check_consistency(p, i);
2230 if (get_partition_start_from_dev_start(pe) < first[i])
2231 printf("Warning: bad start-of-data in "
2232 "partition %u\n", i + 1);
2233 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2235 total += last[i] + 1 - first[i];
2236 for (j = 0; j < i; j++) {
2237 if ((first[i] >= first[j] && first[i] <= last[j])
2238 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2239 printf("Warning: partition %u overlaps "
2240 "partition %u\n", j + 1, i + 1);
2241 total += first[i] >= first[j] ?
2242 first[i] : first[j];
2243 total -= last[i] <= last[j] ?
2250 if (extended_offset) {
2251 struct pte *pex = &ptes[ext_index];
2252 sector_t e_last = get_start_sect(pex->part_table) +
2253 get_nr_sects(pex->part_table) - 1;
2255 for (i = 4; i < g_partitions; i++) {
2257 p = ptes[i].part_table;
2259 if (i != 4 || i + 1 < g_partitions)
2260 printf("Warning: partition %u "
2261 "is empty\n", i + 1);
2262 } else if (first[i] < extended_offset || last[i] > e_last) {
2263 printf("Logical partition %u not entirely in "
2264 "partition %u\n", i + 1, ext_index + 1);
2269 if (total > g_heads * g_sectors * g_cylinders)
2270 printf("Total allocated sectors %u greater than the maximum "
2271 "%u\n", total, g_heads * g_sectors * g_cylinders);
2273 total = g_heads * g_sectors * g_cylinders - total;
2275 printf("%"SECT_FMT"u unallocated sectors\n", total);
2280 add_partition(int n, int sys)
2282 char mesg[256]; /* 48 does not suffice in Japanese */
2283 int i, num_read = 0;
2284 struct partition *p = ptes[n].part_table;
2285 struct partition *q = ptes[ext_index].part_table;
2286 sector_t limit, temp;
2287 sector_t start, stop = 0;
2288 sector_t first[g_partitions], last[g_partitions];
2290 if (p && p->sys_ind) {
2291 printf(msg_part_already_defined, n + 1);
2294 fill_bounds(first, last);
2296 start = sector_offset;
2297 if (display_in_cyl_units || !total_number_of_sectors)
2298 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2300 limit = total_number_of_sectors - 1;
2301 if (extended_offset) {
2302 first[ext_index] = extended_offset;
2303 last[ext_index] = get_start_sect(q) +
2304 get_nr_sects(q) - 1;
2307 start = extended_offset + sector_offset;
2308 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2310 if (display_in_cyl_units)
2311 for (i = 0; i < g_partitions; i++)
2312 first[i] = (cround(first[i]) - 1) * units_per_sector;
2314 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2317 for (i = 0; i < g_partitions; i++) {
2320 if (start == ptes[i].offset_from_dev_start)
2321 start += sector_offset;
2322 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2323 if (start >= first[i] && start <= lastplusoff)
2324 start = lastplusoff + 1;
2328 if (start >= temp+units_per_sector && num_read) {
2329 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2333 if (!num_read && start == temp) {
2334 sector_t saved_start;
2336 saved_start = start;
2337 start = read_int(cround(saved_start), cround(saved_start), cround(limit), 0, mesg);
2338 if (display_in_cyl_units) {
2339 start = (start - 1) * units_per_sector;
2340 if (start < saved_start)
2341 start = saved_start;
2345 } while (start != temp || !num_read);
2346 if (n > 4) { /* NOT for fifth partition */
2347 struct pte *pe = &ptes[n];
2349 pe->offset_from_dev_start = start - sector_offset;
2350 if (pe->offset_from_dev_start == extended_offset) { /* must be corrected */
2351 pe->offset_from_dev_start++;
2352 if (sector_offset == 1)
2357 for (i = 0; i < g_partitions; i++) {
2358 struct pte *pe = &ptes[i];
2360 if (start < pe->offset_from_dev_start && limit >= pe->offset_from_dev_start)
2361 limit = pe->offset_from_dev_start - 1;
2362 if (start < first[i] && limit >= first[i])
2363 limit = first[i] - 1;
2365 if (start > limit) {
2366 printf("No free sectors available\n");
2371 if (cround(start) == cround(limit)) {
2374 snprintf(mesg, sizeof(mesg),
2375 "Last %s or +size or +sizeM or +sizeK",
2376 str_units(SINGULAR));
2377 stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg);
2378 if (display_in_cyl_units) {
2379 stop = stop * units_per_sector - 1;
2385 set_partition(n, 0, start, stop, sys);
2387 set_partition(n - 1, 1, ptes[n].offset_from_dev_start, stop, EXTENDED);
2389 if (IS_EXTENDED(sys)) {
2390 struct pte *pe4 = &ptes[4];
2391 struct pte *pen = &ptes[n];
2394 pen->ext_pointer = p;
2395 pe4->offset_from_dev_start = extended_offset = start;
2396 pe4->sectorbuffer = xzalloc(sector_size);
2397 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2398 pe4->ext_pointer = pe4->part_table + 1;
2407 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2408 struct pte *pe = &ptes[g_partitions];
2410 pe->sectorbuffer = xzalloc(sector_size);
2411 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2412 pe->ext_pointer = pe->part_table + 1;
2413 pe->offset_from_dev_start = 0;
2417 add_partition(g_partitions - 1, LINUX_NATIVE);
2423 int i, free_primary = 0;
2425 if (warn_geometry())
2429 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2433 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2437 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2438 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2439 "table first (use 'o'). This will destroy the present disk contents.\n");
2443 for (i = 0; i < 4; i++)
2444 free_primary += !ptes[i].part_table->sys_ind;
2446 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2447 printf("The maximum number of partitions has been created\n");
2451 if (!free_primary) {
2452 if (extended_offset)
2455 printf("You must delete some partition and add "
2456 "an extended partition first\n");
2459 snprintf(line, sizeof(line),
2462 " p primary partition (1-4)\n",
2464 "l logical (5 or over)" : "e extended"));
2466 c = read_nonempty(line);
2467 if ((c | 0x20) == 'p') {
2468 i = get_nonexisting_partition(0, 4);
2470 add_partition(i, LINUX_NATIVE);
2473 if (c == 'l' && extended_offset) {
2477 if (c == 'e' && !extended_offset) {
2478 i = get_nonexisting_partition(0, 4);
2480 add_partition(i, EXTENDED);
2483 printf("Invalid partition number "
2484 "for type '%c'\n", c);
2495 for (i = 0; i < 3; i++)
2496 if (ptes[i].changed)
2497 ptes[3].changed = 1;
2498 for (i = 3; i < g_partitions; i++) {
2499 struct pte *pe = &ptes[i];
2502 write_part_table_flag(pe->sectorbuffer);
2503 write_sector(pe->offset_from_dev_start, pe->sectorbuffer);
2507 else if (LABEL_IS_SGI) {
2508 /* no test on change? the printf below might be mistaken */
2511 else if (LABEL_IS_SUN) {
2514 for (i = 0; i < 8; i++)
2515 if (ptes[i].changed)
2521 printf("The partition table has been altered!\n\n");
2522 reread_partition_table(1);
2526 reread_partition_table(int leave)
2530 printf("Calling ioctl() to re-read partition table\n");
2532 /* sleep(2); Huh? */
2533 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2534 "WARNING: rereading partition table "
2535 "failed, kernel still uses old table");
2539 "\nWARNING: If you have created or modified any DOS 6.x\n"
2540 "partitions, please see the fdisk manual page for additional\n"
2545 if (ENABLE_FEATURE_CLEAN_UP)
2550 #endif /* FEATURE_FDISK_WRITABLE */
2552 #if ENABLE_FEATURE_FDISK_ADVANCED
2553 #define MAX_PER_LINE 16
2555 print_buffer(char *pbuffer)
2559 for (i = 0, l = 0; i < sector_size; i++, l++) {
2561 printf("0x%03X:", i);
2562 printf(" %02X", (unsigned char) pbuffer[i]);
2563 if (l == MAX_PER_LINE - 1) {
2578 printf("Device: %s\n", disk_device);
2579 if (LABEL_IS_SGI || LABEL_IS_SUN)
2580 print_buffer(MBRbuffer);
2582 for (i = 3; i < g_partitions; i++)
2583 print_buffer(ptes[i].sectorbuffer);
2588 move_begin(unsigned i)
2590 struct pte *pe = &ptes[i];
2591 struct partition *p = pe->part_table;
2592 sector_t new, first, nr_sects;
2594 if (warn_geometry())
2596 nr_sects = get_nr_sects(p);
2597 if (!p->sys_ind || !nr_sects || IS_EXTENDED(p->sys_ind)) {
2598 printf("Partition %u has no data area\n", i + 1);
2601 first = get_partition_start_from_dev_start(pe); /* == pe->offset_from_dev_start + get_start_sect(p) */
2602 new = read_int(0 /*was:first*/, first, first + nr_sects - 1, first, "New beginning of data");
2604 sector_t new_relative = new - pe->offset_from_dev_start;
2605 nr_sects += (get_start_sect(p) - new_relative);
2606 set_start_sect(p, new_relative);
2607 set_nr_sects(p, nr_sects);
2608 read_nonempty("Recalculate C/H/S values? (Y/N): ");
2609 if ((line_ptr[0] | 0x20) == 'y')
2610 set_hsc_start_end(p, new, new + nr_sects - 1);
2622 c = 0x20 | read_nonempty("Expert command (m for help): ");
2630 move_begin(get_partition(0, g_partitions));
2633 user_cylinders = g_cylinders =
2634 read_int(1, g_cylinders, 1048576, 0,
2635 "Number of cylinders");
2637 sun_set_ncyl(g_cylinders);
2647 else if (LABEL_IS_SUN)
2649 else if (LABEL_IS_DOS)
2654 fix_partition_table_order();
2657 #if ENABLE_FEATURE_SGI_LABEL
2662 user_heads = g_heads = read_int(1, g_heads, 256, 0, "Number of heads");
2680 if (ENABLE_FEATURE_CLEAN_UP)
2687 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors");
2688 if (dos_compatible_flag) {
2689 sector_offset = g_sectors;
2690 printf("Warning: setting sector offset for DOS "
2699 write_table(); /* does not return */
2703 sun_set_pcylcount();
2710 #endif /* ADVANCED mode */
2713 is_ide_cdrom_or_tape(const char *device)
2717 struct stat statbuf;
2720 /* No device was given explicitly, and we are trying some
2721 likely things. But opening /dev/hdc may produce errors like
2722 "hdc: tray open or drive not ready"
2723 if it happens to be a CD-ROM drive. It even happens that
2724 the process hangs on the attempt to read a music CD.
2725 So try to be careful. This only works since 2.1.73. */
2727 if (strncmp("/dev/hd", device, 7))
2730 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2731 procf = fopen_for_read(buf);
2732 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2733 is_ide = (!strncmp(buf, "cdrom", 5) ||
2734 !strncmp(buf, "tape", 4));
2736 /* Now when this proc file does not exist, skip the
2737 device when it is read-only. */
2738 if (stat(device, &statbuf) == 0)
2739 is_ide = ((statbuf.st_mode & 0222) == 0);
2748 open_list_and_close(const char *device, int user_specified)
2752 disk_device = device;
2753 if (setjmp(listingbuf))
2755 if (!user_specified)
2756 if (is_ide_cdrom_or_tape(device))
2759 /* Open disk_device, save file descriptor to dev_fd */
2761 gb = get_boot(TRY_ONLY);
2762 if (gb > 0) { /* I/O error */
2763 /* Ignore other errors, since we try IDE
2764 and SCSI hard disks which may not be
2765 installed on the system. */
2766 if (user_specified || errno == EACCES)
2767 bb_perror_msg("can't open '%s'", device);
2771 if (gb < 0) { /* no DOS signature */
2772 list_disk_geometry();
2775 #if ENABLE_FEATURE_OSF_LABEL
2776 if (bsd_trydev(device) < 0)
2778 printf("Disk %s doesn't contain a valid "
2779 "partition table\n", device);
2782 #if ENABLE_FEATURE_FDISK_WRITABLE
2783 if (!LABEL_IS_SUN && g_partitions > 4) {
2784 delete_partition(ext_index);
2792 /* for fdisk -l: try all things in /proc/partitions
2793 that look like a partition name (do not end in a digit) */
2795 list_devs_in_proc_partititons(void)
2798 char line[100], ptname[100], devname[120], *s;
2801 procpt = fopen_or_warn("/proc/partitions", "r");
2803 while (fgets(line, sizeof(line), procpt)) {
2804 if (sscanf(line, " %u %u %u %[^\n ]",
2805 &ma, &mi, &sz, ptname) != 4)
2807 for (s = ptname; *s; s++)
2809 /* note: excluding '0': e.g. mmcblk0 is not a partition name! */
2810 if (s[-1] >= '1' && s[-1] <= '9')
2812 sprintf(devname, "/dev/%s", ptname);
2813 open_list_and_close(devname, 0);
2815 #if ENABLE_FEATURE_CLEAN_UP
2820 #if ENABLE_FEATURE_FDISK_WRITABLE
2822 unknown_command(int c)
2824 printf("%c: unknown command\n", c);
2828 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2829 int fdisk_main(int argc UNUSED_PARAM, char **argv)
2834 * fdisk -l [-b sectorsize] [-u] device ...
2835 * fdisk -s [partition] ...
2836 * fdisk [-b sectorsize] [-u] device
2838 * Options -C, -H, -S set the geometry.
2842 close_dev_fd(); /* needed: fd 3 must not stay closed */
2844 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2845 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2846 §or_size, &user_cylinders, &user_heads, &user_sectors);
2849 /* Ugly: this sector size is really per device,
2850 * so cannot be combined with multiple disks,
2851 * and the same goes for the C/H/S options.
2853 if (sector_size < 512
2854 || sector_size > 0x10000
2855 || (sector_size & (sector_size-1)) /* not power of 2 */
2860 user_set_sector_size = 1;
2862 if (user_heads <= 0 || user_heads >= 256)
2864 if (user_sectors <= 0 || user_sectors >= 64)
2867 display_in_cyl_units = 0; // -u
2869 #if ENABLE_FEATURE_FDISK_WRITABLE
2876 open_list_and_close(*argv, 1);
2879 /* we don't have device names, */
2880 /* use /proc/partitions instead */
2881 list_devs_in_proc_partititons();
2884 #if ENABLE_FEATURE_FDISK_WRITABLE
2888 #if ENABLE_FEATURE_FDISK_BLKSIZE
2895 for (j = 0; argv[j]; j++) {
2896 unsigned long long size;
2897 fd = xopen(argv[j], O_RDONLY);
2898 size = bb_BLKGETSIZE_sectors(fd) / 2;
2901 printf("%llu\n", size);
2903 printf("%s: %llu\n", argv[j], size);
2909 #if ENABLE_FEATURE_FDISK_WRITABLE
2910 if (!argv[0] || argv[1])
2913 disk_device = argv[0];
2914 get_boot(OPEN_MAIN);
2917 /* OSF label, and no DOS label */
2918 printf("Detected an OSF/1 disklabel on %s, entering "
2919 "disklabel mode\n", disk_device);
2921 /*Why do we do this? It seems to be counter-intuitive*/
2922 current_label_type = LABEL_DOS;
2923 /* If we return we may want to make an empty DOS label? */
2929 c = 0x20 | read_nonempty("Command (m for help): ");
2933 toggle_active(get_partition(1, g_partitions));
2934 else if (LABEL_IS_SUN)
2935 toggle_sunflags(get_partition(1, g_partitions),
2937 else if (LABEL_IS_SGI)
2938 sgi_set_bootpartition(
2939 get_partition(1, g_partitions));
2945 printf("\nThe current boot file is: %s\n",
2946 sgi_get_bootfile());
2947 if (read_maybe_empty("Please enter the name of the "
2948 "new boot file: ") == '\n')
2949 printf("Boot file unchanged\n");
2951 sgi_set_bootfile(line_ptr);
2953 #if ENABLE_FEATURE_OSF_LABEL
2960 toggle_dos_compatibility_flag();
2961 else if (LABEL_IS_SUN)
2962 toggle_sunflags(get_partition(1, g_partitions),
2964 else if (LABEL_IS_SGI)
2965 sgi_set_swappartition(
2966 get_partition(1, g_partitions));
2973 /* If sgi_label then don't use get_existing_partition,
2974 let the user select a partition, since
2975 get_existing_partition() only works for Linux-like
2977 if (!LABEL_IS_SGI) {
2978 j = get_existing_partition(1, g_partitions);
2980 j = get_partition(1, g_partitions);
2983 delete_partition(j);
2992 list_types(get_sys_types());
3007 if (ENABLE_FEATURE_CLEAN_UP)
3012 #if ENABLE_FEATURE_SUN_LABEL
3026 write_table(); /* does not return */
3028 #if ENABLE_FEATURE_FDISK_ADVANCED
3031 printf("\n\tSorry, no experts menu for SGI "
3032 "partition tables available\n\n");
3043 #endif /* FEATURE_FDISK_WRITABLE */