Changes for kernel and Busybox
[tomato.git] / release / src / router / busybox / util-linux / fdisk.c
blob6eb797cd386e85c305173ca8b931af819d6723f2
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 GPLv2 or later, see file LICENSE in this source tree.
8 */
10 /* Looks like someone forgot to add this to config system */
11 //usage:#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
12 //usage:# define ENABLE_FEATURE_FDISK_BLKSIZE 0
13 //usage:# define IF_FEATURE_FDISK_BLKSIZE(a)
14 //usage:#endif
15 //usage:
16 //usage:#define fdisk_trivial_usage
17 //usage: "[-ul" IF_FEATURE_FDISK_BLKSIZE("s") "] "
18 //usage: "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK"
19 //usage:#define fdisk_full_usage "\n\n"
20 //usage: "Change partition table\n"
21 //usage: "\n -u Start and End are in sectors (instead of cylinders)"
22 //usage: "\n -l Show partition table for each DISK, then exit"
23 //usage: IF_FEATURE_FDISK_BLKSIZE(
24 //usage: "\n -s Show partition sizes in kb for each DISK, then exit"
25 //usage: )
26 //usage: "\n -b 2048 (for certain MO disks) use 2048-byte sectors"
27 //usage: "\n -C CYLINDERS Set number of cylinders/heads/sectors"
28 //usage: "\n -H HEADS"
29 //usage: "\n -S SECTORS"
31 #ifndef _LARGEFILE64_SOURCE
32 /* For lseek64 */
33 # define _LARGEFILE64_SOURCE
34 #endif
35 #include <assert.h> /* assert */
36 #include <sys/mount.h>
37 #if !defined(BLKSSZGET)
38 # define BLKSSZGET _IO(0x12, 104)
39 #endif
40 #if !defined(BLKGETSIZE64)
41 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
42 #endif
43 #include "libbb.h"
45 #if BB_LITTLE_ENDIAN
46 # define inline_if_little_endian ALWAYS_INLINE
47 #else
48 # define inline_if_little_endian /* nothing */
49 #endif
52 /* Looks like someone forgot to add this to config system */
53 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
54 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
55 # define IF_FEATURE_FDISK_BLKSIZE(a)
56 #endif
58 #define DEFAULT_SECTOR_SIZE 512
59 #define DEFAULT_SECTOR_SIZE_STR "512"
60 #define MAX_SECTOR_SIZE 2048
61 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
62 #define MAXIMUM_PARTS 60
64 #define ACTIVE_FLAG 0x80
66 #define EXTENDED 0x05
67 #define WIN98_EXTENDED 0x0f
68 #define LINUX_PARTITION 0x81
69 #define LINUX_SWAP 0x82
70 #define LINUX_NATIVE 0x83
71 #define LINUX_EXTENDED 0x85
72 #define LINUX_LVM 0x8e
73 #define LINUX_RAID 0xfd
76 enum {
77 OPT_b = 1 << 0,
78 OPT_C = 1 << 1,
79 OPT_H = 1 << 2,
80 OPT_l = 1 << 3,
81 OPT_S = 1 << 4,
82 OPT_u = 1 << 5,
83 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
87 typedef unsigned long long ullong;
88 /* Used for sector numbers. Partition formats we know
89 * do not support more than 2^32 sectors
91 typedef uint32_t sector_t;
92 #if UINT_MAX == 4294967295
93 # define SECT_FMT ""
94 #elif ULONG_MAX == 4294967295
95 # define SECT_FMT "l"
96 #else
97 # error Cant detect sizeof(uint32_t)
98 #endif
100 struct hd_geometry {
101 unsigned char heads;
102 unsigned char sectors;
103 unsigned short cylinders;
104 unsigned long start;
107 #define HDIO_GETGEO 0x0301 /* get device geometry */
109 static const char msg_building_new_label[] ALIGN1 =
110 "Building a new %s. Changes will remain in memory only,\n"
111 "until you decide to write them. After that the previous content\n"
112 "won't be recoverable.\n\n";
114 static const char msg_part_already_defined[] ALIGN1 =
115 "Partition %u is already defined, delete it before re-adding\n";
118 struct partition {
119 unsigned char boot_ind; /* 0x80 - active */
120 unsigned char head; /* starting head */
121 unsigned char sector; /* starting sector */
122 unsigned char cyl; /* starting cylinder */
123 unsigned char sys_ind; /* what partition type */
124 unsigned char end_head; /* end head */
125 unsigned char end_sector; /* end sector */
126 unsigned char end_cyl; /* end cylinder */
127 unsigned char start4[4]; /* starting sector counting from 0 */
128 unsigned char size4[4]; /* nr of sectors in partition */
129 } PACKED;
132 * per partition table entry data
134 * The four primary partitions have the same sectorbuffer (MBRbuffer)
135 * and have NULL ext_pointer.
136 * Each logical partition table entry has two pointers, one for the
137 * partition and one link to the next one.
139 struct pte {
140 struct partition *part_table; /* points into sectorbuffer */
141 struct partition *ext_pointer; /* points into sectorbuffer */
142 sector_t offset_from_dev_start; /* disk sector number */
143 char *sectorbuffer; /* disk sector contents */
144 #if ENABLE_FEATURE_FDISK_WRITABLE
145 char changed; /* boolean */
146 #endif
149 #define unable_to_open "can't open '%s'"
150 #define unable_to_read "can't read from %s"
151 #define unable_to_seek "can't seek on %s"
153 enum label_type {
154 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT
157 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
159 #if ENABLE_FEATURE_SUN_LABEL
160 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
161 #define STATIC_SUN static
162 #else
163 #define LABEL_IS_SUN 0
164 #define STATIC_SUN extern
165 #endif
167 #if ENABLE_FEATURE_SGI_LABEL
168 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
169 #define STATIC_SGI static
170 #else
171 #define LABEL_IS_SGI 0
172 #define STATIC_SGI extern
173 #endif
175 #if ENABLE_FEATURE_AIX_LABEL
176 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
177 #define STATIC_AIX static
178 #else
179 #define LABEL_IS_AIX 0
180 #define STATIC_AIX extern
181 #endif
183 #if ENABLE_FEATURE_OSF_LABEL
184 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
185 #define STATIC_OSF static
186 #else
187 #define LABEL_IS_OSF 0
188 #define STATIC_OSF extern
189 #endif
191 #if ENABLE_FEATURE_GPT_LABEL
192 #define LABEL_IS_GPT (LABEL_GPT == current_label_type)
193 #define STATIC_GPT static
194 #else
195 #define LABEL_IS_GPT 0
196 #define STATIC_GPT extern
197 #endif
199 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
201 static void update_units(void);
202 #if ENABLE_FEATURE_FDISK_WRITABLE
203 static void change_units(void);
204 static void reread_partition_table(int leave);
205 static void delete_partition(int i);
206 static unsigned get_partition(int warn, unsigned max);
207 static void list_types(const char *const *sys);
208 static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
209 #endif
210 static const char *partition_type(unsigned char type);
211 static void get_geometry(void);
212 static void read_pte(struct pte *pe, sector_t offset);
213 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
214 static int get_boot(enum action what);
215 #else
216 static int get_boot(void);
217 #endif
219 #define PLURAL 0
220 #define SINGULAR 1
222 static sector_t get_start_sect(const struct partition *p);
223 static sector_t get_nr_sects(const struct partition *p);
225 /* DOS partition types */
227 static const char *const i386_sys_types[] = {
228 "\x00" "Empty",
229 "\x01" "FAT12",
230 "\x04" "FAT16 <32M",
231 "\x05" "Extended", /* DOS 3.3+ extended partition */
232 "\x06" "FAT16", /* DOS 16-bit >=32M */
233 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
234 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
235 "\x0b" "Win95 FAT32",
236 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
237 "\x0e" "Win95 FAT16 (LBA)",
238 "\x0f" "Win95 Ext'd (LBA)",
239 "\x11" "Hidden FAT12",
240 "\x12" "Compaq diagnostics",
241 "\x14" "Hidden FAT16 <32M",
242 "\x16" "Hidden FAT16",
243 "\x17" "Hidden HPFS/NTFS",
244 "\x1b" "Hidden Win95 FAT32",
245 "\x1c" "Hidden W95 FAT32 (LBA)",
246 "\x1e" "Hidden W95 FAT16 (LBA)",
247 "\x3c" "Part.Magic recovery",
248 "\x41" "PPC PReP Boot",
249 "\x42" "SFS",
250 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
251 "\x80" "Old Minix", /* Minix 1.4a and earlier */
252 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
253 "\x82" "Linux swap", /* also Solaris */
254 "\x83" "Linux",
255 "\x84" "OS/2 hidden C: drive",
256 "\x85" "Linux extended",
257 "\x86" "NTFS volume set",
258 "\x87" "NTFS volume set",
259 "\x8e" "Linux LVM",
260 "\x9f" "BSD/OS", /* BSDI */
261 "\xa0" "Thinkpad hibernation",
262 "\xa5" "FreeBSD", /* various BSD flavours */
263 "\xa6" "OpenBSD",
264 "\xa8" "Darwin UFS",
265 "\xa9" "NetBSD",
266 "\xab" "Darwin boot",
267 "\xb7" "BSDI fs",
268 "\xb8" "BSDI swap",
269 "\xbe" "Solaris boot",
270 "\xeb" "BeOS fs",
271 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
272 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
273 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
274 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
275 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
276 autodetect using persistent
277 superblock */
278 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
279 "\x02" "XENIX root",
280 "\x03" "XENIX usr",
281 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
282 "\x09" "AIX bootable", /* AIX data or Coherent */
283 "\x10" "OPUS",
284 "\x18" "AST SmartSleep",
285 "\x24" "NEC DOS",
286 "\x39" "Plan 9",
287 "\x40" "Venix 80286",
288 "\x4d" "QNX4.x",
289 "\x4e" "QNX4.x 2nd part",
290 "\x4f" "QNX4.x 3rd part",
291 "\x50" "OnTrack DM",
292 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
293 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
294 "\x53" "OnTrack DM6 Aux3",
295 "\x54" "OnTrackDM6",
296 "\x55" "EZ-Drive",
297 "\x56" "Golden Bow",
298 "\x5c" "Priam Edisk",
299 "\x61" "SpeedStor",
300 "\x64" "Novell Netware 286",
301 "\x65" "Novell Netware 386",
302 "\x70" "DiskSecure Multi-Boot",
303 "\x75" "PC/IX",
304 "\x93" "Amoeba",
305 "\x94" "Amoeba BBT", /* (bad block table) */
306 "\xa7" "NeXTSTEP",
307 "\xbb" "Boot Wizard hidden",
308 "\xc1" "DRDOS/sec (FAT-12)",
309 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
310 "\xc6" "DRDOS/sec (FAT-16)",
311 "\xc7" "Syrinx",
312 "\xda" "Non-FS data",
313 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
314 Concurrent DOS or CTOS */
315 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
316 "\xdf" "BootIt", /* BootIt EMBRM */
317 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
318 extended partition */
319 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
320 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
321 partition < 1024 cyl. */
322 "\xf1" "SpeedStor",
323 "\xf4" "SpeedStor", /* SpeedStor large partition */
324 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
325 "\xff" "BBT", /* Xenix Bad Block Table */
326 #endif
327 NULL
330 enum {
331 dev_fd = 3 /* the disk */
334 /* Globals */
335 struct globals {
336 char *line_ptr;
338 const char *disk_device;
339 int g_partitions; // = 4; /* maximum partition + 1 */
340 unsigned units_per_sector; // = 1;
341 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
342 unsigned user_set_sector_size;
343 unsigned sector_offset; // = 1;
344 unsigned g_heads, g_sectors, g_cylinders;
345 smallint /* enum label_type */ current_label_type;
346 smallint display_in_cyl_units; // = 1;
347 #if ENABLE_FEATURE_OSF_LABEL
348 smallint possibly_osf_label;
349 #endif
351 smallint listing; /* no aborts for fdisk -l */
352 smallint dos_compatible_flag; // = 1;
353 #if ENABLE_FEATURE_FDISK_WRITABLE
354 //int dos_changed;
355 smallint nowarn; /* no warnings for fdisk -l/-s */
356 #endif
357 int ext_index; /* the prime extended partition */
358 unsigned user_cylinders, user_heads, user_sectors;
359 unsigned pt_heads, pt_sectors;
360 unsigned kern_heads, kern_sectors;
361 sector_t extended_offset; /* offset of link pointers */
362 sector_t total_number_of_sectors;
364 jmp_buf listingbuf;
365 char line_buffer[80];
366 char partname_buffer[80];
367 /* Raw disk label. For DOS-type partition tables the MBR,
368 * with descriptions of the primary partitions. */
369 char MBRbuffer[MAX_SECTOR_SIZE];
370 /* Partition tables */
371 struct pte ptes[MAXIMUM_PARTS];
373 #define G (*ptr_to_globals)
374 #define line_ptr (G.line_ptr )
375 #define disk_device (G.disk_device )
376 #define g_partitions (G.g_partitions )
377 #define units_per_sector (G.units_per_sector )
378 #define sector_size (G.sector_size )
379 #define user_set_sector_size (G.user_set_sector_size)
380 #define sector_offset (G.sector_offset )
381 #define g_heads (G.g_heads )
382 #define g_sectors (G.g_sectors )
383 #define g_cylinders (G.g_cylinders )
384 #define current_label_type (G.current_label_type )
385 #define display_in_cyl_units (G.display_in_cyl_units)
386 #define possibly_osf_label (G.possibly_osf_label )
387 #define listing (G.listing )
388 #define dos_compatible_flag (G.dos_compatible_flag )
389 #define nowarn (G.nowarn )
390 #define ext_index (G.ext_index )
391 #define user_cylinders (G.user_cylinders )
392 #define user_heads (G.user_heads )
393 #define user_sectors (G.user_sectors )
394 #define pt_heads (G.pt_heads )
395 #define pt_sectors (G.pt_sectors )
396 #define kern_heads (G.kern_heads )
397 #define kern_sectors (G.kern_sectors )
398 #define extended_offset (G.extended_offset )
399 #define total_number_of_sectors (G.total_number_of_sectors)
400 #define listingbuf (G.listingbuf )
401 #define line_buffer (G.line_buffer )
402 #define partname_buffer (G.partname_buffer)
403 #define MBRbuffer (G.MBRbuffer )
404 #define ptes (G.ptes )
405 #define INIT_G() do { \
406 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
407 sector_size = DEFAULT_SECTOR_SIZE; \
408 sector_offset = 1; \
409 g_partitions = 4; \
410 display_in_cyl_units = 1; \
411 units_per_sector = 1; \
412 dos_compatible_flag = 1; \
413 } while (0)
416 /* TODO: move to libbb? */
417 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
418 * disks > 2^32 sectors
420 static sector_t bb_BLKGETSIZE_sectors(int fd)
422 uint64_t v64;
423 unsigned long longsectors;
425 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
426 /* Got bytes, convert to sectors */
427 v64 /= sector_size;
428 if (v64 != (sector_t)v64) {
429 ret_trunc:
430 /* Not only DOS, but all other partition tables
431 * we support can't record more than 32 bit
432 * sector counts or offsets
434 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
435 v64 = (uint32_t)-1L;
437 return v64;
439 /* Needs temp of type long */
440 if (ioctl(fd, BLKGETSIZE, &longsectors)) {
441 /* Perhaps this is a disk image */
442 off_t sz = lseek(fd, 0, SEEK_END);
443 longsectors = 0;
444 if (sz > 0)
445 longsectors = (uoff_t)sz / sector_size;
446 lseek(fd, 0, SEEK_SET);
448 if (sizeof(long) > sizeof(sector_t)
449 && longsectors != (sector_t)longsectors
451 goto ret_trunc;
453 return longsectors;
457 #define IS_EXTENDED(i) \
458 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
460 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
462 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
464 #define pt_offset(b, n) \
465 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
467 #define sector(s) ((s) & 0x3f)
469 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
471 #define hsc2sector(h,s,c) \
472 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
474 static void
475 close_dev_fd(void)
477 /* Not really closing, but making sure it is open, and to harmless place */
478 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
482 * Return partition name - uses static storage
484 static const char *
485 partname(const char *dev, int pno, int lth)
487 const char *p;
488 int w, wp;
489 int bufsiz;
490 char *bufp;
492 bufp = partname_buffer;
493 bufsiz = sizeof(partname_buffer);
495 w = strlen(dev);
496 p = "";
498 if (isdigit(dev[w-1]))
499 p = "p";
501 /* devfs kludge - note: fdisk partition names are not supposed
502 to equal kernel names, so there is no reason to do this */
503 if (strcmp(dev + w - 4, "disc") == 0) {
504 w -= 4;
505 p = "part";
508 wp = strlen(p);
510 if (lth) {
511 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
512 lth-wp-2, w, dev, p, pno);
513 } else {
514 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
516 return bufp;
519 static ALWAYS_INLINE struct partition *
520 get_part_table(int i)
522 return ptes[i].part_table;
525 static const char *
526 str_units(int n)
527 { /* n==1: use singular */
528 if (n == 1)
529 return display_in_cyl_units ? "cylinder" : "sector";
530 return display_in_cyl_units ? "cylinders" : "sectors";
533 static int
534 valid_part_table_flag(const char *mbuffer)
536 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
539 static void fdisk_fatal(const char *why)
541 if (listing) {
542 close_dev_fd();
543 longjmp(listingbuf, 1);
545 bb_error_msg_and_die(why, disk_device);
548 static void
549 seek_sector(sector_t secno)
551 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
552 off64_t off = (off64_t)secno * sector_size;
553 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
554 fdisk_fatal(unable_to_seek);
555 #else
556 uint64_t off = (uint64_t)secno * sector_size;
557 if (off > MAXINT(off_t)
558 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
560 fdisk_fatal(unable_to_seek);
562 #endif
565 #if ENABLE_FEATURE_FDISK_WRITABLE
566 /* Read line; return 0 or first printable char */
567 static int
568 read_line(const char *prompt)
570 int sz;
572 sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
573 if (sz <= 0)
574 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
576 if (line_buffer[sz-1] == '\n')
577 line_buffer[--sz] = '\0';
579 line_ptr = line_buffer;
580 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
581 line_ptr++;
582 return *line_ptr;
585 static void
586 set_all_unchanged(void)
588 int i;
590 for (i = 0; i < MAXIMUM_PARTS; i++)
591 ptes[i].changed = 0;
594 static ALWAYS_INLINE void
595 set_changed(int i)
597 ptes[i].changed = 1;
600 static ALWAYS_INLINE void
601 write_part_table_flag(char *b)
603 b[510] = 0x55;
604 b[511] = 0xaa;
607 static char
608 read_nonempty(const char *mesg)
610 while (!read_line(mesg))
611 continue;
612 return *line_ptr;
615 static char
616 read_maybe_empty(const char *mesg)
618 if (!read_line(mesg)) {
619 line_ptr = line_buffer;
620 line_ptr[0] = '\n';
621 line_ptr[1] = '\0';
623 return line_ptr[0];
626 static int
627 read_hex(const char *const *sys)
629 unsigned long v;
630 while (1) {
631 read_nonempty("Hex code (type L to list codes): ");
632 if ((line_ptr[0] | 0x20) == 'l') {
633 list_types(sys);
634 continue;
636 v = bb_strtoul(line_ptr, NULL, 16);
637 if (v <= 0xff)
638 return v;
642 static void
643 write_sector(sector_t secno, const void *buf)
645 seek_sector(secno);
646 xwrite(dev_fd, buf, sector_size);
648 #endif /* FEATURE_FDISK_WRITABLE */
651 #include "fdisk_aix.c"
653 struct sun_partition {
654 unsigned char info[128]; /* Informative text string */
655 unsigned char spare0[14];
656 struct sun_info {
657 unsigned char spare1;
658 unsigned char id;
659 unsigned char spare2;
660 unsigned char flags;
661 } infos[8];
662 unsigned char spare1[246]; /* Boot information etc. */
663 unsigned short rspeed; /* Disk rotational speed */
664 unsigned short pcylcount; /* Physical cylinder count */
665 unsigned short sparecyl; /* extra sects per cylinder */
666 unsigned char spare2[4]; /* More magic... */
667 unsigned short ilfact; /* Interleave factor */
668 unsigned short ncyl; /* Data cylinder count */
669 unsigned short nacyl; /* Alt. cylinder count */
670 unsigned short ntrks; /* Tracks per cylinder */
671 unsigned short nsect; /* Sectors per track */
672 unsigned char spare3[4]; /* Even more magic... */
673 struct sun_partinfo {
674 uint32_t start_cylinder;
675 uint32_t num_sectors;
676 } partitions[8];
677 unsigned short magic; /* Magic number */
678 unsigned short csum; /* Label xor'd checksum */
679 } FIX_ALIASING;
680 typedef struct sun_partition sun_partition;
681 #define sunlabel ((sun_partition *)MBRbuffer)
682 STATIC_OSF void bsd_select(void);
683 STATIC_OSF void xbsd_print_disklabel(int);
684 #include "fdisk_osf.c"
686 STATIC_GPT void gpt_list_table(int xtra);
687 #include "fdisk_gpt.c"
689 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
690 static uint16_t
691 fdisk_swap16(uint16_t x)
693 return (x << 8) | (x >> 8);
696 static uint32_t
697 fdisk_swap32(uint32_t x)
699 return (x << 24) |
700 ((x & 0xFF00) << 8) |
701 ((x & 0xFF0000) >> 8) |
702 (x >> 24);
704 #endif
706 STATIC_SGI const char *const sgi_sys_types[];
707 STATIC_SGI unsigned sgi_get_num_sectors(int i);
708 STATIC_SGI int sgi_get_sysid(int i);
709 STATIC_SGI void sgi_delete_partition(int i);
710 STATIC_SGI void sgi_change_sysid(int i, int sys);
711 STATIC_SGI void sgi_list_table(int xtra);
712 #if ENABLE_FEATURE_FDISK_ADVANCED
713 STATIC_SGI void sgi_set_xcyl(void);
714 #endif
715 STATIC_SGI int verify_sgi(int verbose);
716 STATIC_SGI void sgi_add_partition(int n, int sys);
717 STATIC_SGI void sgi_set_swappartition(int i);
718 STATIC_SGI const char *sgi_get_bootfile(void);
719 STATIC_SGI void sgi_set_bootfile(const char* aFile);
720 STATIC_SGI void create_sgiinfo(void);
721 STATIC_SGI void sgi_write_table(void);
722 STATIC_SGI void sgi_set_bootpartition(int i);
723 #include "fdisk_sgi.c"
725 STATIC_SUN const char *const sun_sys_types[];
726 STATIC_SUN void sun_delete_partition(int i);
727 STATIC_SUN void sun_change_sysid(int i, int sys);
728 STATIC_SUN void sun_list_table(int xtra);
729 STATIC_SUN void add_sun_partition(int n, int sys);
730 #if ENABLE_FEATURE_FDISK_ADVANCED
731 STATIC_SUN void sun_set_alt_cyl(void);
732 STATIC_SUN void sun_set_ncyl(int cyl);
733 STATIC_SUN void sun_set_xcyl(void);
734 STATIC_SUN void sun_set_ilfact(void);
735 STATIC_SUN void sun_set_rspeed(void);
736 STATIC_SUN void sun_set_pcylcount(void);
737 #endif
738 STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
739 STATIC_SUN void verify_sun(void);
740 STATIC_SUN void sun_write_table(void);
741 #include "fdisk_sun.c"
744 static inline_if_little_endian unsigned
745 read4_little_endian(const unsigned char *cp)
747 uint32_t v;
748 move_from_unaligned32(v, cp);
749 return SWAP_LE32(v);
752 static sector_t
753 get_start_sect(const struct partition *p)
755 return read4_little_endian(p->start4);
758 static sector_t
759 get_nr_sects(const struct partition *p)
761 return read4_little_endian(p->size4);
764 #if ENABLE_FEATURE_FDISK_WRITABLE
765 /* start_sect and nr_sects are stored little endian on all machines */
766 /* moreover, they are not aligned correctly */
767 static inline_if_little_endian void
768 store4_little_endian(unsigned char *cp, unsigned val)
770 uint32_t v = SWAP_LE32(val);
771 move_to_unaligned32(cp, v);
774 static void
775 set_start_sect(struct partition *p, unsigned start_sect)
777 store4_little_endian(p->start4, start_sect);
780 static void
781 set_nr_sects(struct partition *p, unsigned nr_sects)
783 store4_little_endian(p->size4, nr_sects);
785 #endif
787 /* Allocate a buffer and read a partition table sector */
788 static void
789 read_pte(struct pte *pe, sector_t offset)
791 pe->offset_from_dev_start = offset;
792 pe->sectorbuffer = xzalloc(sector_size);
793 seek_sector(offset);
794 /* xread would make us abort - bad for fdisk -l */
795 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
796 fdisk_fatal(unable_to_read);
797 #if ENABLE_FEATURE_FDISK_WRITABLE
798 pe->changed = 0;
799 #endif
800 pe->part_table = pe->ext_pointer = NULL;
803 static sector_t
804 get_partition_start_from_dev_start(const struct pte *pe)
806 return pe->offset_from_dev_start + get_start_sect(pe->part_table);
809 #if ENABLE_FEATURE_FDISK_WRITABLE
811 * Avoid warning about DOS partitions when no DOS partition was changed.
812 * Here a heuristic "is probably dos partition".
813 * We might also do the opposite and warn in all cases except
814 * for "is probably nondos partition".
816 #ifdef UNUSED
817 static int
818 is_dos_partition(int t)
820 return (t == 1 || t == 4 || t == 6 ||
821 t == 0x0b || t == 0x0c || t == 0x0e ||
822 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
823 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
824 t == 0xc1 || t == 0xc4 || t == 0xc6);
826 #endif
828 static void
829 menu(void)
831 puts("Command Action");
832 if (LABEL_IS_SUN) {
833 puts("a\ttoggle a read only flag"); /* sun */
834 puts("b\tedit bsd disklabel");
835 puts("c\ttoggle the mountable flag"); /* sun */
836 puts("d\tdelete a partition");
837 puts("l\tlist known partition types");
838 puts("n\tadd a new partition");
839 puts("o\tcreate a new empty DOS partition table");
840 puts("p\tprint the partition table");
841 puts("q\tquit without saving changes");
842 puts("s\tcreate a new empty Sun disklabel"); /* sun */
843 puts("t\tchange a partition's system id");
844 puts("u\tchange display/entry units");
845 puts("v\tverify the partition table");
846 puts("w\twrite table to disk and exit");
847 #if ENABLE_FEATURE_FDISK_ADVANCED
848 puts("x\textra functionality (experts only)");
849 #endif
850 } else if (LABEL_IS_SGI) {
851 puts("a\tselect bootable partition"); /* sgi flavour */
852 puts("b\tedit bootfile entry"); /* sgi */
853 puts("c\tselect sgi swap partition"); /* sgi flavour */
854 puts("d\tdelete a partition");
855 puts("l\tlist known partition types");
856 puts("n\tadd a new partition");
857 puts("o\tcreate a new empty DOS partition table");
858 puts("p\tprint the partition table");
859 puts("q\tquit without saving changes");
860 puts("s\tcreate a new empty Sun disklabel"); /* sun */
861 puts("t\tchange a partition's system id");
862 puts("u\tchange display/entry units");
863 puts("v\tverify the partition table");
864 puts("w\twrite table to disk and exit");
865 } else if (LABEL_IS_AIX) {
866 puts("o\tcreate a new empty DOS partition table");
867 puts("q\tquit without saving changes");
868 puts("s\tcreate a new empty Sun disklabel"); /* sun */
869 } else if (LABEL_IS_GPT) {
870 puts("o\tcreate a new empty DOS partition table");
871 puts("p\tprint the partition table");
872 puts("q\tquit without saving changes");
873 puts("s\tcreate a new empty Sun disklabel"); /* sun */
874 } else {
875 puts("a\ttoggle a bootable flag");
876 puts("b\tedit bsd disklabel");
877 puts("c\ttoggle the dos compatibility flag");
878 puts("d\tdelete a partition");
879 puts("l\tlist known partition types");
880 puts("n\tadd a new partition");
881 puts("o\tcreate a new empty DOS partition table");
882 puts("p\tprint the partition table");
883 puts("q\tquit without saving changes");
884 puts("s\tcreate a new empty Sun disklabel"); /* sun */
885 puts("t\tchange a partition's system id");
886 puts("u\tchange display/entry units");
887 puts("v\tverify the partition table");
888 puts("w\twrite table to disk and exit");
889 #if ENABLE_FEATURE_FDISK_ADVANCED
890 puts("x\textra functionality (experts only)");
891 #endif
894 #endif /* FEATURE_FDISK_WRITABLE */
897 #if ENABLE_FEATURE_FDISK_ADVANCED
898 static void
899 xmenu(void)
901 puts("Command Action");
902 if (LABEL_IS_SUN) {
903 puts("a\tchange number of alternate cylinders"); /*sun*/
904 puts("c\tchange number of cylinders");
905 puts("d\tprint the raw data in the partition table");
906 puts("e\tchange number of extra sectors per cylinder");/*sun*/
907 puts("h\tchange number of heads");
908 puts("i\tchange interleave factor"); /*sun*/
909 puts("o\tchange rotation speed (rpm)"); /*sun*/
910 puts("p\tprint the partition table");
911 puts("q\tquit without saving changes");
912 puts("r\treturn to main menu");
913 puts("s\tchange number of sectors/track");
914 puts("v\tverify the partition table");
915 puts("w\twrite table to disk and exit");
916 puts("y\tchange number of physical cylinders"); /*sun*/
917 } else if (LABEL_IS_SGI) {
918 puts("b\tmove beginning of data in a partition"); /* !sun */
919 puts("c\tchange number of cylinders");
920 puts("d\tprint the raw data in the partition table");
921 puts("e\tlist extended partitions"); /* !sun */
922 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
923 puts("h\tchange number of heads");
924 puts("p\tprint the partition table");
925 puts("q\tquit without saving changes");
926 puts("r\treturn to main menu");
927 puts("s\tchange number of sectors/track");
928 puts("v\tverify the partition table");
929 puts("w\twrite table to disk and exit");
930 } else if (LABEL_IS_AIX) {
931 puts("b\tmove beginning of data in a partition"); /* !sun */
932 puts("c\tchange number of cylinders");
933 puts("d\tprint the raw data in the partition table");
934 puts("e\tlist extended partitions"); /* !sun */
935 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
936 puts("h\tchange number of heads");
937 puts("p\tprint the partition table");
938 puts("q\tquit without saving changes");
939 puts("r\treturn to main menu");
940 puts("s\tchange number of sectors/track");
941 puts("v\tverify the partition table");
942 puts("w\twrite table to disk and exit");
943 } else {
944 puts("b\tmove beginning of data in a partition"); /* !sun */
945 puts("c\tchange number of cylinders");
946 puts("d\tprint the raw data in the partition table");
947 puts("e\tlist extended partitions"); /* !sun */
948 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
949 #if ENABLE_FEATURE_SGI_LABEL
950 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
951 #endif
952 puts("h\tchange number of heads");
953 puts("p\tprint the partition table");
954 puts("q\tquit without saving changes");
955 puts("r\treturn to main menu");
956 puts("s\tchange number of sectors/track");
957 puts("v\tverify the partition table");
958 puts("w\twrite table to disk and exit");
961 #endif /* ADVANCED mode */
963 #if ENABLE_FEATURE_FDISK_WRITABLE
964 static const char *const *
965 get_sys_types(void)
967 return (
968 LABEL_IS_SUN ? sun_sys_types :
969 LABEL_IS_SGI ? sgi_sys_types :
970 i386_sys_types);
972 #else
973 #define get_sys_types() i386_sys_types
974 #endif
976 static const char *
977 partition_type(unsigned char type)
979 int i;
980 const char *const *types = get_sys_types();
982 for (i = 0; types[i]; i++)
983 if ((unsigned char)types[i][0] == type)
984 return types[i] + 1;
986 return "Unknown";
989 static int
990 is_cleared_partition(const struct partition *p)
992 /* We consider partition "cleared" only if it has only zeros */
993 const char *cp = (const char *)p;
994 int cnt = sizeof(*p);
995 char bits = 0;
996 while (--cnt >= 0)
997 bits |= *cp++;
998 return (bits == 0);
1001 static void
1002 clear_partition(struct partition *p)
1004 if (p)
1005 memset(p, 0, sizeof(*p));
1008 #if ENABLE_FEATURE_FDISK_WRITABLE
1009 static int
1010 get_sysid(int i)
1012 return LABEL_IS_SUN ? sunlabel->infos[i].id :
1013 (LABEL_IS_SGI ? sgi_get_sysid(i) :
1014 ptes[i].part_table->sys_ind);
1017 static void
1018 list_types(const char *const *sys)
1020 enum { COLS = 3 };
1022 unsigned last[COLS];
1023 unsigned done, next, size;
1024 int i;
1026 for (size = 0; sys[size]; size++)
1027 continue;
1029 done = 0;
1030 for (i = COLS-1; i >= 0; i--) {
1031 done += (size + i - done) / (i + 1);
1032 last[COLS-1 - i] = done;
1035 i = done = next = 0;
1036 do {
1037 printf("%c%2x %-22.22s", i ? ' ' : '\n',
1038 (unsigned char)sys[next][0],
1039 sys[next] + 1);
1040 next = last[i++] + done;
1041 if (i >= COLS || next >= last[i]) {
1042 i = 0;
1043 next = ++done;
1045 } while (done < last[0]);
1046 bb_putchar('\n');
1049 #define set_hsc(h, s, c, sector) do \
1051 s = sector % g_sectors + 1; \
1052 sector /= g_sectors; \
1053 h = sector % g_heads; \
1054 sector /= g_heads; \
1055 c = sector & 0xff; \
1056 s |= (sector >> 2) & 0xc0; \
1057 } while (0)
1059 static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop)
1061 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1062 start = g_heads * g_sectors * 1024 - 1;
1063 set_hsc(p->head, p->sector, p->cyl, start);
1065 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1066 stop = g_heads * g_sectors * 1024 - 1;
1067 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1070 static void
1071 set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
1073 struct partition *p;
1074 sector_t offset;
1076 if (doext) {
1077 p = ptes[i].ext_pointer;
1078 offset = extended_offset;
1079 } else {
1080 p = ptes[i].part_table;
1081 offset = ptes[i].offset_from_dev_start;
1083 p->boot_ind = 0;
1084 p->sys_ind = sysid;
1085 set_start_sect(p, start - offset);
1086 set_nr_sects(p, stop - start + 1);
1087 set_hsc_start_end(p, start, stop);
1088 ptes[i].changed = 1;
1090 #endif
1092 static int
1093 warn_geometry(void)
1095 if (g_heads && g_sectors && g_cylinders)
1096 return 0;
1098 printf("Unknown value(s) for:");
1099 if (!g_heads)
1100 printf(" heads");
1101 if (!g_sectors)
1102 printf(" sectors");
1103 if (!g_cylinders)
1104 printf(" cylinders");
1105 printf(
1106 #if ENABLE_FEATURE_FDISK_WRITABLE
1107 " (settable in the extra functions menu)"
1108 #endif
1109 "\n");
1110 return 1;
1113 static void
1114 update_units(void)
1116 int cyl_units = g_heads * g_sectors;
1118 if (display_in_cyl_units && cyl_units)
1119 units_per_sector = cyl_units;
1120 else
1121 units_per_sector = 1; /* in sectors */
1124 #if ENABLE_FEATURE_FDISK_WRITABLE
1125 static void
1126 warn_cylinders(void)
1128 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1129 printf("\n"
1130 "The number of cylinders for this disk is set to %u.\n"
1131 "There is nothing wrong with that, but this is larger than 1024,\n"
1132 "and could in certain setups cause problems with:\n"
1133 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1134 "2) booting and partitioning software from other OSs\n"
1135 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1136 g_cylinders);
1138 #endif
1140 static void
1141 read_extended(int ext)
1143 int i;
1144 struct pte *pex;
1145 struct partition *p, *q;
1147 ext_index = ext;
1148 pex = &ptes[ext];
1149 pex->ext_pointer = pex->part_table;
1151 p = pex->part_table;
1152 if (!get_start_sect(p)) {
1153 printf("Bad offset in primary extended partition\n");
1154 return;
1157 while (IS_EXTENDED(p->sys_ind)) {
1158 struct pte *pe = &ptes[g_partitions];
1160 if (g_partitions >= MAXIMUM_PARTS) {
1161 /* This is not a Linux restriction, but
1162 this program uses arrays of size MAXIMUM_PARTS.
1163 Do not try to 'improve' this test. */
1164 struct pte *pre = &ptes[g_partitions - 1];
1165 #if ENABLE_FEATURE_FDISK_WRITABLE
1166 printf("Warning: deleting partitions after %u\n",
1167 g_partitions);
1168 pre->changed = 1;
1169 #endif
1170 clear_partition(pre->ext_pointer);
1171 return;
1174 read_pte(pe, extended_offset + get_start_sect(p));
1176 if (!extended_offset)
1177 extended_offset = get_start_sect(p);
1179 q = p = pt_offset(pe->sectorbuffer, 0);
1180 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1181 if (IS_EXTENDED(p->sys_ind)) {
1182 if (pe->ext_pointer)
1183 printf("Warning: extra link "
1184 "pointer in partition table"
1185 " %u\n", g_partitions + 1);
1186 else
1187 pe->ext_pointer = p;
1188 } else if (p->sys_ind) {
1189 if (pe->part_table)
1190 printf("Warning: ignoring extra "
1191 "data in partition table"
1192 " %u\n", g_partitions + 1);
1193 else
1194 pe->part_table = p;
1198 /* very strange code here... */
1199 if (!pe->part_table) {
1200 if (q != pe->ext_pointer)
1201 pe->part_table = q;
1202 else
1203 pe->part_table = q + 1;
1205 if (!pe->ext_pointer) {
1206 if (q != pe->part_table)
1207 pe->ext_pointer = q;
1208 else
1209 pe->ext_pointer = q + 1;
1212 p = pe->ext_pointer;
1213 g_partitions++;
1216 #if ENABLE_FEATURE_FDISK_WRITABLE
1217 /* remove empty links */
1218 remove:
1219 for (i = 4; i < g_partitions; i++) {
1220 struct pte *pe = &ptes[i];
1222 if (!get_nr_sects(pe->part_table)
1223 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1225 printf("Omitting empty partition (%u)\n", i+1);
1226 delete_partition(i);
1227 goto remove; /* numbering changed */
1230 #endif
1233 #if ENABLE_FEATURE_FDISK_WRITABLE
1234 static void
1235 create_doslabel(void)
1237 printf(msg_building_new_label, "DOS disklabel");
1239 current_label_type = LABEL_DOS;
1240 #if ENABLE_FEATURE_OSF_LABEL
1241 possibly_osf_label = 0;
1242 #endif
1243 g_partitions = 4;
1245 memset(&MBRbuffer[510 - 4*16], 0, 4*16);
1246 write_part_table_flag(MBRbuffer);
1247 extended_offset = 0;
1248 set_all_unchanged();
1249 set_changed(0);
1250 get_boot(CREATE_EMPTY_DOS);
1252 #endif
1254 static void
1255 get_sectorsize(void)
1257 if (!user_set_sector_size) {
1258 int arg;
1259 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1260 sector_size = arg;
1261 if (sector_size != DEFAULT_SECTOR_SIZE)
1262 printf("Note: sector size is %u "
1263 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1264 sector_size);
1268 static void
1269 get_kernel_geometry(void)
1271 struct hd_geometry geometry;
1273 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1274 kern_heads = geometry.heads;
1275 kern_sectors = geometry.sectors;
1276 /* never use geometry.cylinders - it is truncated */
1280 static void
1281 get_partition_table_geometry(void)
1283 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1284 struct partition *p;
1285 int i, h, s, hh, ss;
1286 int first = 1;
1287 int bad = 0;
1289 if (!(valid_part_table_flag((char*)bufp)))
1290 return;
1292 hh = ss = 0;
1293 for (i = 0; i < 4; i++) {
1294 p = pt_offset(bufp, i);
1295 if (p->sys_ind != 0) {
1296 h = p->end_head + 1;
1297 s = (p->end_sector & 077);
1298 if (first) {
1299 hh = h;
1300 ss = s;
1301 first = 0;
1302 } else if (hh != h || ss != s)
1303 bad = 1;
1307 if (!first && !bad) {
1308 pt_heads = hh;
1309 pt_sectors = ss;
1313 static void
1314 get_geometry(void)
1316 int sec_fac;
1318 get_sectorsize();
1319 sec_fac = sector_size / 512;
1320 #if ENABLE_FEATURE_SUN_LABEL
1321 guess_device_type();
1322 #endif
1323 g_heads = g_cylinders = g_sectors = 0;
1324 kern_heads = kern_sectors = 0;
1325 pt_heads = pt_sectors = 0;
1327 get_kernel_geometry();
1328 get_partition_table_geometry();
1330 g_heads = user_heads ? user_heads :
1331 pt_heads ? pt_heads :
1332 kern_heads ? kern_heads : 255;
1333 g_sectors = user_sectors ? user_sectors :
1334 pt_sectors ? pt_sectors :
1335 kern_sectors ? kern_sectors : 63;
1336 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1338 sector_offset = 1;
1339 if (dos_compatible_flag)
1340 sector_offset = g_sectors;
1342 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1343 if (!g_cylinders)
1344 g_cylinders = user_cylinders;
1348 * Opens disk_device and optionally reads MBR.
1349 * If what == OPEN_MAIN:
1350 * Open device, read MBR. Abort program on short read. Create empty
1351 * disklabel if the on-disk structure is invalid (WRITABLE mode).
1352 * If what == TRY_ONLY:
1353 * Open device, read MBR. Return an error if anything is out of place.
1354 * Do not create an empty disklabel. This is used for the "list"
1355 * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
1356 * If what == CREATE_EMPTY_*:
1357 * This means that get_boot() was called recursively from create_*label().
1358 * Do not re-open the device; just set up the ptes array and print
1359 * geometry warnings.
1361 * Returns:
1362 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1363 * 0: found or created label
1364 * 1: I/O error
1366 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1367 static int get_boot(enum action what)
1368 #else
1369 static int get_boot(void)
1370 #define get_boot(what) get_boot()
1371 #endif
1373 int i, fd;
1375 g_partitions = 4;
1376 for (i = 0; i < 4; i++) {
1377 struct pte *pe = &ptes[i];
1378 pe->part_table = pt_offset(MBRbuffer, i);
1379 pe->ext_pointer = NULL;
1380 pe->offset_from_dev_start = 0;
1381 pe->sectorbuffer = MBRbuffer;
1382 #if ENABLE_FEATURE_FDISK_WRITABLE
1383 pe->changed = (what == CREATE_EMPTY_DOS);
1384 #endif
1387 #if ENABLE_FEATURE_FDISK_WRITABLE
1388 // ALERT! highly idiotic design!
1389 // We end up here when we call get_boot() recursively
1390 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1391 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1392 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1393 // So skip opening device _again_...
1394 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1395 goto created_table;
1397 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1399 if (fd < 0) {
1400 fd = open(disk_device, O_RDONLY);
1401 if (fd < 0) {
1402 if (what == TRY_ONLY)
1403 return 1;
1404 fdisk_fatal(unable_to_open);
1406 printf("'%s' is opened for read only\n", disk_device);
1408 xmove_fd(fd, dev_fd);
1409 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1410 if (what == TRY_ONLY) {
1411 close_dev_fd();
1412 return 1;
1414 fdisk_fatal(unable_to_read);
1416 #else
1417 fd = open(disk_device, O_RDONLY);
1418 if (fd < 0)
1419 return 1;
1420 if (512 != full_read(fd, MBRbuffer, 512)) {
1421 close(fd);
1422 return 1;
1424 xmove_fd(fd, dev_fd);
1425 #endif
1427 get_geometry();
1428 update_units();
1430 #if ENABLE_FEATURE_SUN_LABEL
1431 if (check_sun_label())
1432 return 0;
1433 #endif
1434 #if ENABLE_FEATURE_SGI_LABEL
1435 if (check_sgi_label())
1436 return 0;
1437 #endif
1438 #if ENABLE_FEATURE_AIX_LABEL
1439 if (check_aix_label())
1440 return 0;
1441 #endif
1442 #if ENABLE_FEATURE_GPT_LABEL
1443 if (check_gpt_label())
1444 return 0;
1445 #endif
1446 #if ENABLE_FEATURE_OSF_LABEL
1447 if (check_osf_label()) {
1448 possibly_osf_label = 1;
1449 if (!valid_part_table_flag(MBRbuffer)) {
1450 current_label_type = LABEL_OSF;
1451 return 0;
1453 printf("This disk has both DOS and BSD magic.\n"
1454 "Give the 'b' command to go to BSD mode.\n");
1456 #endif
1458 #if !ENABLE_FEATURE_FDISK_WRITABLE
1459 if (!valid_part_table_flag(MBRbuffer))
1460 return -1;
1461 #else
1462 if (!valid_part_table_flag(MBRbuffer)) {
1463 if (what == OPEN_MAIN) {
1464 printf("Device contains neither a valid DOS "
1465 "partition table, nor Sun, SGI, OSF or GPT "
1466 "disklabel\n");
1467 #ifdef __sparc__
1468 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1469 #else
1470 create_doslabel();
1471 #endif
1472 return 0;
1474 /* TRY_ONLY: */
1475 return -1;
1477 created_table:
1478 #endif /* FEATURE_FDISK_WRITABLE */
1481 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1482 warn_geometry();
1484 for (i = 0; i < 4; i++) {
1485 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1486 if (g_partitions != 4)
1487 printf("Ignoring extra extended "
1488 "partition %u\n", i + 1);
1489 else
1490 read_extended(i);
1494 for (i = 3; i < g_partitions; i++) {
1495 struct pte *pe = &ptes[i];
1496 if (!valid_part_table_flag(pe->sectorbuffer)) {
1497 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1498 "table %u will be corrected by w(rite)\n",
1499 pe->sectorbuffer[510],
1500 pe->sectorbuffer[511],
1501 i + 1);
1502 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1506 return 0;
1509 #if ENABLE_FEATURE_FDISK_WRITABLE
1511 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1512 * If the user hits Enter, DFLT is returned.
1513 * Answers like +10 are interpreted as offsets from BASE.
1515 * There is no default if DFLT is not between LOW and HIGH.
1517 static sector_t
1518 read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
1520 sector_t value;
1521 int default_ok = 1;
1522 const char *fmt = "%s (%u-%u, default %u): ";
1524 if (dflt < low || dflt > high) {
1525 fmt = "%s (%u-%u): ";
1526 default_ok = 0;
1529 while (1) {
1530 int use_default = default_ok;
1532 /* ask question and read answer */
1533 do {
1534 printf(fmt, mesg, low, high, dflt);
1535 read_maybe_empty("");
1536 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1537 && *line_ptr != '-' && *line_ptr != '+');
1539 if (*line_ptr == '+' || *line_ptr == '-') {
1540 int minus = (*line_ptr == '-');
1541 int absolute = 0;
1543 value = atoi(line_ptr + 1);
1545 /* (1) if 2nd char is digit, use_default = 0.
1546 * (2) move line_ptr to first non-digit. */
1547 while (isdigit(*++line_ptr))
1548 use_default = 0;
1550 switch (*line_ptr) {
1551 case 'c':
1552 case 'C':
1553 if (!display_in_cyl_units)
1554 value *= g_heads * g_sectors;
1555 break;
1556 case 'K':
1557 absolute = 1024;
1558 break;
1559 case 'k':
1560 absolute = 1000;
1561 break;
1562 case 'm':
1563 case 'M':
1564 absolute = 1000000;
1565 break;
1566 case 'g':
1567 case 'G':
1568 absolute = 1000000000;
1569 break;
1570 default:
1571 break;
1573 if (absolute) {
1574 ullong bytes;
1575 unsigned long unit;
1577 bytes = (ullong) value * absolute;
1578 unit = sector_size * units_per_sector;
1579 bytes += unit/2; /* round */
1580 bytes /= unit;
1581 value = bytes;
1583 if (minus)
1584 value = -value;
1585 value += base;
1586 } else {
1587 value = atoi(line_ptr);
1588 while (isdigit(*line_ptr)) {
1589 line_ptr++;
1590 use_default = 0;
1593 if (use_default) {
1594 value = dflt;
1595 printf("Using default value %u\n", value);
1597 if (value >= low && value <= high)
1598 break;
1599 printf("Value is out of range\n");
1601 return value;
1604 static unsigned
1605 get_partition(int warn, unsigned max)
1607 struct pte *pe;
1608 unsigned i;
1610 i = read_int(1, 0, max, 0, "Partition number") - 1;
1611 pe = &ptes[i];
1613 if (warn) {
1614 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1615 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1616 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1618 printf("Warning: partition %u has empty type\n", i+1);
1621 return i;
1624 static int
1625 get_existing_partition(int warn, unsigned max)
1627 int pno = -1;
1628 unsigned i;
1630 for (i = 0; i < max; i++) {
1631 struct pte *pe = &ptes[i];
1632 struct partition *p = pe->part_table;
1634 if (p && !is_cleared_partition(p)) {
1635 if (pno >= 0)
1636 goto not_unique;
1637 pno = i;
1640 if (pno >= 0) {
1641 printf("Selected partition %u\n", pno+1);
1642 return pno;
1644 printf("No partition is defined yet!\n");
1645 return -1;
1647 not_unique:
1648 return get_partition(warn, max);
1651 static int
1652 get_nonexisting_partition(int warn, unsigned max)
1654 int pno = -1;
1655 unsigned i;
1657 for (i = 0; i < max; i++) {
1658 struct pte *pe = &ptes[i];
1659 struct partition *p = pe->part_table;
1661 if (p && is_cleared_partition(p)) {
1662 if (pno >= 0)
1663 goto not_unique;
1664 pno = i;
1667 if (pno >= 0) {
1668 printf("Selected partition %u\n", pno+1);
1669 return pno;
1671 printf("All primary partitions have been defined already!\n");
1672 return -1;
1674 not_unique:
1675 return get_partition(warn, max);
1679 static void
1680 change_units(void)
1682 display_in_cyl_units = !display_in_cyl_units;
1683 update_units();
1684 printf("Changing display/entry units to %s\n",
1685 str_units(PLURAL));
1688 static void
1689 toggle_active(int i)
1691 struct pte *pe = &ptes[i];
1692 struct partition *p = pe->part_table;
1694 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1695 printf("WARNING: Partition %u is an extended partition\n", i + 1);
1696 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1697 pe->changed = 1;
1700 static void
1701 toggle_dos_compatibility_flag(void)
1703 dos_compatible_flag = 1 - dos_compatible_flag;
1704 if (dos_compatible_flag) {
1705 sector_offset = g_sectors;
1706 printf("DOS Compatibility flag is set\n");
1707 } else {
1708 sector_offset = 1;
1709 printf("DOS Compatibility flag is not set\n");
1713 static void
1714 delete_partition(int i)
1716 struct pte *pe = &ptes[i];
1717 struct partition *p = pe->part_table;
1718 struct partition *q = pe->ext_pointer;
1720 /* Note that for the fifth partition (i == 4) we don't actually
1721 * decrement partitions.
1724 if (warn_geometry())
1725 return; /* C/H/S not set */
1726 pe->changed = 1;
1728 if (LABEL_IS_SUN) {
1729 sun_delete_partition(i);
1730 return;
1732 if (LABEL_IS_SGI) {
1733 sgi_delete_partition(i);
1734 return;
1737 if (i < 4) {
1738 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1739 g_partitions = 4;
1740 ptes[ext_index].ext_pointer = NULL;
1741 extended_offset = 0;
1743 clear_partition(p);
1744 return;
1747 if (!q->sys_ind && i > 4) {
1748 /* the last one in the chain - just delete */
1749 --g_partitions;
1750 --i;
1751 clear_partition(ptes[i].ext_pointer);
1752 ptes[i].changed = 1;
1753 } else {
1754 /* not the last one - further ones will be moved down */
1755 if (i > 4) {
1756 /* delete this link in the chain */
1757 p = ptes[i-1].ext_pointer;
1758 *p = *q;
1759 set_start_sect(p, get_start_sect(q));
1760 set_nr_sects(p, get_nr_sects(q));
1761 ptes[i-1].changed = 1;
1762 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1763 /* the first logical in a longer chain */
1764 pe = &ptes[5];
1766 if (pe->part_table) /* prevent SEGFAULT */
1767 set_start_sect(pe->part_table,
1768 get_partition_start_from_dev_start(pe) -
1769 extended_offset);
1770 pe->offset_from_dev_start = extended_offset;
1771 pe->changed = 1;
1774 if (g_partitions > 5) {
1775 g_partitions--;
1776 while (i < g_partitions) {
1777 ptes[i] = ptes[i+1];
1778 i++;
1780 } else {
1781 /* the only logical: clear only */
1782 clear_partition(ptes[i].part_table);
1787 static void
1788 change_sysid(void)
1790 int i, sys, origsys;
1791 struct partition *p;
1793 /* If sgi_label then don't use get_existing_partition,
1794 let the user select a partition, since get_existing_partition()
1795 only works for Linux like partition tables. */
1796 if (!LABEL_IS_SGI) {
1797 i = get_existing_partition(0, g_partitions);
1798 } else {
1799 i = get_partition(0, g_partitions);
1801 if (i == -1)
1802 return;
1803 p = ptes[i].part_table;
1804 origsys = sys = get_sysid(i);
1806 /* if changing types T to 0 is allowed, then
1807 the reverse change must be allowed, too */
1808 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1809 printf("Partition %u does not exist yet!\n", i + 1);
1810 return;
1812 while (1) {
1813 sys = read_hex(get_sys_types());
1815 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1816 printf("Type 0 means free space to many systems\n"
1817 "(but not to Linux). Having partitions of\n"
1818 "type 0 is probably unwise.\n");
1819 /* break; */
1822 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1823 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1824 printf("You cannot change a partition into"
1825 " an extended one or vice versa\n");
1826 break;
1830 if (sys < 256) {
1831 #if ENABLE_FEATURE_SUN_LABEL
1832 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1833 printf("Consider leaving partition 3 "
1834 "as Whole disk (5),\n"
1835 "as SunOS/Solaris expects it and "
1836 "even Linux likes it\n\n");
1837 #endif
1838 #if ENABLE_FEATURE_SGI_LABEL
1839 if (LABEL_IS_SGI &&
1841 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1842 (i == 8 && sys != 0)
1845 printf("Consider leaving partition 9 "
1846 "as volume header (0),\nand "
1847 "partition 11 as entire volume (6)"
1848 "as IRIX expects it\n\n");
1850 #endif
1851 if (sys == origsys)
1852 break;
1853 if (LABEL_IS_SUN) {
1854 sun_change_sysid(i, sys);
1855 } else if (LABEL_IS_SGI) {
1856 sgi_change_sysid(i, sys);
1857 } else
1858 p->sys_ind = sys;
1860 printf("Changed system type of partition %u "
1861 "to %x (%s)\n", i + 1, sys,
1862 partition_type(sys));
1863 ptes[i].changed = 1;
1864 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1865 // dos_changed = 1;
1866 break;
1870 #endif /* FEATURE_FDISK_WRITABLE */
1873 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1874 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1875 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1876 * Lubkin Oct. 1991). */
1878 static void
1879 linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1881 int spc = g_heads * g_sectors;
1883 *c = ls / spc;
1884 ls = ls % spc;
1885 *h = ls / g_sectors;
1886 *s = ls % g_sectors + 1; /* sectors count from 1 */
1889 static void
1890 check_consistency(const struct partition *p, int partition)
1892 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1893 unsigned pec, peh, pes; /* physical ending c, h, s */
1894 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1895 unsigned lec, leh, les; /* logical ending c, h, s */
1897 if (!g_heads || !g_sectors || (partition >= 4))
1898 return; /* do not check extended partitions */
1900 /* physical beginning c, h, s */
1901 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1902 pbh = p->head;
1903 pbs = p->sector & 0x3f;
1905 /* physical ending c, h, s */
1906 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1907 peh = p->end_head;
1908 pes = p->end_sector & 0x3f;
1910 /* compute logical beginning (c, h, s) */
1911 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1913 /* compute logical ending (c, h, s) */
1914 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1916 /* Same physical / logical beginning? */
1917 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1918 printf("Partition %u has different physical/logical "
1919 "beginnings (non-Linux?):\n", partition + 1);
1920 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
1921 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
1924 /* Same physical / logical ending? */
1925 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1926 printf("Partition %u has different physical/logical "
1927 "endings:\n", partition + 1);
1928 printf(" phys=(%u, %u, %u) ", pec, peh, pes);
1929 printf("logical=(%u, %u, %u)\n", lec, leh, les);
1932 /* Ending on cylinder boundary? */
1933 if (peh != (g_heads - 1) || pes != g_sectors) {
1934 printf("Partition %u does not end on cylinder boundary\n",
1935 partition + 1);
1939 static void
1940 list_disk_geometry(void)
1942 ullong bytes = ((ullong)total_number_of_sectors * sector_size);
1943 long megabytes = bytes / 1000000;
1945 if (megabytes < 10000)
1946 printf("\nDisk %s: %lu MB, %llu bytes\n",
1947 disk_device, megabytes, bytes);
1948 else
1949 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1950 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1951 printf("%u heads, %u sectors/track, %u cylinders",
1952 g_heads, g_sectors, g_cylinders);
1953 if (units_per_sector == 1)
1954 printf(", total %"SECT_FMT"u sectors",
1955 total_number_of_sectors);
1956 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1957 str_units(PLURAL),
1958 units_per_sector, sector_size, units_per_sector * sector_size);
1962 * Check whether partition entries are ordered by their starting positions.
1963 * Return 0 if OK. Return i if partition i should have been earlier.
1964 * Two separate checks: primary and logical partitions.
1966 static int
1967 wrong_p_order(int *prev)
1969 const struct pte *pe;
1970 const struct partition *p;
1971 sector_t last_p_start_pos = 0, p_start_pos;
1972 unsigned i, last_i = 0;
1974 for (i = 0; i < g_partitions; i++) {
1975 if (i == 4) {
1976 last_i = 4;
1977 last_p_start_pos = 0;
1979 pe = &ptes[i];
1980 p = pe->part_table;
1981 if (p->sys_ind) {
1982 p_start_pos = get_partition_start_from_dev_start(pe);
1984 if (last_p_start_pos > p_start_pos) {
1985 if (prev)
1986 *prev = last_i;
1987 return i;
1990 last_p_start_pos = p_start_pos;
1991 last_i = i;
1994 return 0;
1997 #if ENABLE_FEATURE_FDISK_ADVANCED
1999 * Fix the chain of logicals.
2000 * extended_offset is unchanged, the set of sectors used is unchanged
2001 * The chain is sorted so that sectors increase, and so that
2002 * starting sectors increase.
2004 * After this it may still be that cfdisk doesnt like the table.
2005 * (This is because cfdisk considers expanded parts, from link to
2006 * end of partition, and these may still overlap.)
2007 * Now
2008 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
2009 * may help.
2011 static void
2012 fix_chain_of_logicals(void)
2014 int j, oj, ojj, sj, sjj;
2015 struct partition *pj,*pjj,tmp;
2017 /* Stage 1: sort sectors but leave sector of part 4 */
2018 /* (Its sector is the global extended_offset.) */
2019 stage1:
2020 for (j = 5; j < g_partitions - 1; j++) {
2021 oj = ptes[j].offset_from_dev_start;
2022 ojj = ptes[j+1].offset_from_dev_start;
2023 if (oj > ojj) {
2024 ptes[j].offset_from_dev_start = ojj;
2025 ptes[j+1].offset_from_dev_start = oj;
2026 pj = ptes[j].part_table;
2027 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
2028 pjj = ptes[j+1].part_table;
2029 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
2030 set_start_sect(ptes[j-1].ext_pointer,
2031 ojj-extended_offset);
2032 set_start_sect(ptes[j].ext_pointer,
2033 oj-extended_offset);
2034 goto stage1;
2038 /* Stage 2: sort starting sectors */
2039 stage2:
2040 for (j = 4; j < g_partitions - 1; j++) {
2041 pj = ptes[j].part_table;
2042 pjj = ptes[j+1].part_table;
2043 sj = get_start_sect(pj);
2044 sjj = get_start_sect(pjj);
2045 oj = ptes[j].offset_from_dev_start;
2046 ojj = ptes[j+1].offset_from_dev_start;
2047 if (oj+sj > ojj+sjj) {
2048 tmp = *pj;
2049 *pj = *pjj;
2050 *pjj = tmp;
2051 set_start_sect(pj, ojj+sjj-oj);
2052 set_start_sect(pjj, oj+sj-ojj);
2053 goto stage2;
2057 /* Probably something was changed */
2058 for (j = 4; j < g_partitions; j++)
2059 ptes[j].changed = 1;
2063 static void
2064 fix_partition_table_order(void)
2066 struct pte *pei, *pek;
2067 int i,k;
2069 if (!wrong_p_order(NULL)) {
2070 printf("Ordering is already correct\n\n");
2071 return;
2074 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
2075 /* partition i should have come earlier, move it */
2076 /* We have to move data in the MBR */
2077 struct partition *pi, *pk, *pe, pbuf;
2078 pei = &ptes[i];
2079 pek = &ptes[k];
2081 pe = pei->ext_pointer;
2082 pei->ext_pointer = pek->ext_pointer;
2083 pek->ext_pointer = pe;
2085 pi = pei->part_table;
2086 pk = pek->part_table;
2088 memmove(&pbuf, pi, sizeof(struct partition));
2089 memmove(pi, pk, sizeof(struct partition));
2090 memmove(pk, &pbuf, sizeof(struct partition));
2092 pei->changed = pek->changed = 1;
2095 if (i)
2096 fix_chain_of_logicals();
2098 printf("Done.\n");
2100 #endif
2102 static void
2103 list_table(int xtra)
2105 const struct partition *p;
2106 int i, w;
2108 if (LABEL_IS_SUN) {
2109 sun_list_table(xtra);
2110 return;
2112 if (LABEL_IS_SGI) {
2113 sgi_list_table(xtra);
2114 return;
2116 if (LABEL_IS_GPT) {
2117 gpt_list_table(xtra);
2118 return;
2121 list_disk_geometry();
2123 if (LABEL_IS_OSF) {
2124 xbsd_print_disklabel(xtra);
2125 return;
2128 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2129 but if the device name ends in a digit, say /dev/foo1,
2130 then the partition is called /dev/foo1p3. */
2131 w = strlen(disk_device);
2132 if (w && isdigit(disk_device[w-1]))
2133 w++;
2134 if (w < 5)
2135 w = 5;
2137 // 1 12345678901 12345678901 12345678901 12
2138 printf("%*s Boot Start End Blocks Id System\n",
2139 w+1, "Device");
2141 for (i = 0; i < g_partitions; i++) {
2142 const struct pte *pe = &ptes[i];
2143 sector_t psects;
2144 sector_t pblocks;
2145 unsigned podd;
2147 p = pe->part_table;
2148 if (!p || is_cleared_partition(p))
2149 continue;
2151 psects = get_nr_sects(p);
2152 pblocks = psects;
2153 podd = 0;
2155 if (sector_size < 1024) {
2156 pblocks /= (1024 / sector_size);
2157 podd = psects % (1024 / sector_size);
2159 if (sector_size > 1024)
2160 pblocks *= (sector_size / 1024);
2162 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
2163 partname(disk_device, i+1, w+2),
2164 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2165 ? '*' : '?',
2166 cround(get_partition_start_from_dev_start(pe)), /* start */
2167 cround(get_partition_start_from_dev_start(pe) + psects /* end */
2168 - (psects ? 1 : 0)),
2169 pblocks, podd ? '+' : ' ', /* odd flag on end */
2170 p->sys_ind, /* type id */
2171 partition_type(p->sys_ind)); /* type name */
2173 check_consistency(p, i);
2176 /* Is partition table in disk order? It need not be, but... */
2177 /* partition table entries are not checked for correct order
2178 * if this is a sgi, sun or aix labeled disk... */
2179 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2180 /* FIXME */
2181 printf("\nPartition table entries are not in disk order\n");
2185 #if ENABLE_FEATURE_FDISK_ADVANCED
2186 static void
2187 x_list_table(int extend)
2189 const struct pte *pe;
2190 const struct partition *p;
2191 int i;
2193 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2194 disk_device, g_heads, g_sectors, g_cylinders);
2195 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2196 for (i = 0; i < g_partitions; i++) {
2197 pe = &ptes[i];
2198 p = (extend ? pe->ext_pointer : pe->part_table);
2199 if (p != NULL) {
2200 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
2201 i + 1, p->boot_ind, p->head,
2202 sector(p->sector),
2203 cylinder(p->sector, p->cyl), p->end_head,
2204 sector(p->end_sector),
2205 cylinder(p->end_sector, p->end_cyl),
2206 get_start_sect(p), get_nr_sects(p),
2207 p->sys_ind);
2208 if (p->sys_ind)
2209 check_consistency(p, i);
2213 #endif
2215 #if ENABLE_FEATURE_FDISK_WRITABLE
2216 static void
2217 fill_bounds(sector_t *first, sector_t *last)
2219 unsigned i;
2220 const struct pte *pe = &ptes[0];
2221 const struct partition *p;
2223 for (i = 0; i < g_partitions; pe++,i++) {
2224 p = pe->part_table;
2225 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2226 first[i] = 0xffffffff;
2227 last[i] = 0;
2228 } else {
2229 first[i] = get_partition_start_from_dev_start(pe);
2230 last[i] = first[i] + get_nr_sects(p) - 1;
2235 static void
2236 check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
2238 sector_t total, real_s, real_c;
2240 real_s = sector(s) - 1;
2241 real_c = cylinder(s, c);
2242 total = (real_c * g_sectors + real_s) * g_heads + h;
2243 if (!total)
2244 printf("Partition %u contains sector 0\n", n);
2245 if (h >= g_heads)
2246 printf("Partition %u: head %u greater than maximum %u\n",
2247 n, h + 1, g_heads);
2248 if (real_s >= g_sectors)
2249 printf("Partition %u: sector %u greater than "
2250 "maximum %u\n", n, s, g_sectors);
2251 if (real_c >= g_cylinders)
2252 printf("Partition %u: cylinder %"SECT_FMT"u greater than "
2253 "maximum %u\n", n, real_c + 1, g_cylinders);
2254 if (g_cylinders <= 1024 && start != total)
2255 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
2256 "total %"SECT_FMT"u\n", n, start, total);
2259 static void
2260 verify(void)
2262 int i, j;
2263 sector_t total = 1;
2264 sector_t first[g_partitions], last[g_partitions];
2265 struct partition *p;
2267 if (warn_geometry())
2268 return;
2270 if (LABEL_IS_SUN) {
2271 verify_sun();
2272 return;
2274 if (LABEL_IS_SGI) {
2275 verify_sgi(1);
2276 return;
2279 fill_bounds(first, last);
2280 for (i = 0; i < g_partitions; i++) {
2281 struct pte *pe = &ptes[i];
2283 p = pe->part_table;
2284 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2285 check_consistency(p, i);
2286 if (get_partition_start_from_dev_start(pe) < first[i])
2287 printf("Warning: bad start-of-data in "
2288 "partition %u\n", i + 1);
2289 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2290 last[i]);
2291 total += last[i] + 1 - first[i];
2292 for (j = 0; j < i; j++) {
2293 if ((first[i] >= first[j] && first[i] <= last[j])
2294 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2295 printf("Warning: partition %u overlaps "
2296 "partition %u\n", j + 1, i + 1);
2297 total += first[i] >= first[j] ?
2298 first[i] : first[j];
2299 total -= last[i] <= last[j] ?
2300 last[i] : last[j];
2306 if (extended_offset) {
2307 struct pte *pex = &ptes[ext_index];
2308 sector_t e_last = get_start_sect(pex->part_table) +
2309 get_nr_sects(pex->part_table) - 1;
2311 for (i = 4; i < g_partitions; i++) {
2312 total++;
2313 p = ptes[i].part_table;
2314 if (!p->sys_ind) {
2315 if (i != 4 || i + 1 < g_partitions)
2316 printf("Warning: partition %u "
2317 "is empty\n", i + 1);
2318 } else if (first[i] < extended_offset || last[i] > e_last) {
2319 printf("Logical partition %u not entirely in "
2320 "partition %u\n", i + 1, ext_index + 1);
2325 if (total > g_heads * g_sectors * g_cylinders)
2326 printf("Total allocated sectors %u greater than the maximum "
2327 "%u\n", total, g_heads * g_sectors * g_cylinders);
2328 else {
2329 total = g_heads * g_sectors * g_cylinders - total;
2330 if (total != 0)
2331 printf("%"SECT_FMT"u unallocated sectors\n", total);
2335 static void
2336 add_partition(int n, int sys)
2338 char mesg[256]; /* 48 does not suffice in Japanese */
2339 int i, num_read = 0;
2340 struct partition *p = ptes[n].part_table;
2341 struct partition *q = ptes[ext_index].part_table;
2342 sector_t limit, temp;
2343 sector_t start, stop = 0;
2344 sector_t first[g_partitions], last[g_partitions];
2346 if (p && p->sys_ind) {
2347 printf(msg_part_already_defined, n + 1);
2348 return;
2350 fill_bounds(first, last);
2351 if (n < 4) {
2352 start = sector_offset;
2353 if (display_in_cyl_units || !total_number_of_sectors)
2354 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
2355 else
2356 limit = total_number_of_sectors - 1;
2357 if (extended_offset) {
2358 first[ext_index] = extended_offset;
2359 last[ext_index] = get_start_sect(q) +
2360 get_nr_sects(q) - 1;
2362 } else {
2363 start = extended_offset + sector_offset;
2364 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2366 if (display_in_cyl_units)
2367 for (i = 0; i < g_partitions; i++)
2368 first[i] = (cround(first[i]) - 1) * units_per_sector;
2370 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2371 do {
2372 temp = start;
2373 for (i = 0; i < g_partitions; i++) {
2374 int lastplusoff;
2376 if (start == ptes[i].offset_from_dev_start)
2377 start += sector_offset;
2378 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2379 if (start >= first[i] && start <= lastplusoff)
2380 start = lastplusoff + 1;
2382 if (start > limit)
2383 break;
2384 if (start >= temp+units_per_sector && num_read) {
2385 printf("Sector %"SECT_FMT"u is already allocated\n", temp);
2386 temp = start;
2387 num_read = 0;
2389 if (!num_read && start == temp) {
2390 sector_t saved_start;
2392 saved_start = start;
2393 start = read_int(cround(saved_start), cround(saved_start), cround(limit), 0, mesg);
2394 if (display_in_cyl_units) {
2395 start = (start - 1) * units_per_sector;
2396 if (start < saved_start)
2397 start = saved_start;
2399 num_read = 1;
2401 } while (start != temp || !num_read);
2402 if (n > 4) { /* NOT for fifth partition */
2403 struct pte *pe = &ptes[n];
2405 pe->offset_from_dev_start = start - sector_offset;
2406 if (pe->offset_from_dev_start == extended_offset) { /* must be corrected */
2407 pe->offset_from_dev_start++;
2408 if (sector_offset == 1)
2409 start++;
2413 for (i = 0; i < g_partitions; i++) {
2414 struct pte *pe = &ptes[i];
2416 if (start < pe->offset_from_dev_start && limit >= pe->offset_from_dev_start)
2417 limit = pe->offset_from_dev_start - 1;
2418 if (start < first[i] && limit >= first[i])
2419 limit = first[i] - 1;
2421 if (start > limit) {
2422 printf("No free sectors available\n");
2423 if (n > 4)
2424 g_partitions--;
2425 return;
2427 if (cround(start) == cround(limit)) {
2428 stop = limit;
2429 } else {
2430 snprintf(mesg, sizeof(mesg),
2431 "Last %s or +size or +sizeM or +sizeK",
2432 str_units(SINGULAR));
2433 stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg);
2434 if (display_in_cyl_units) {
2435 stop = stop * units_per_sector - 1;
2436 if (stop >limit)
2437 stop = limit;
2441 set_partition(n, 0, start, stop, sys);
2442 if (n > 4)
2443 set_partition(n - 1, 1, ptes[n].offset_from_dev_start, stop, EXTENDED);
2445 if (IS_EXTENDED(sys)) {
2446 struct pte *pe4 = &ptes[4];
2447 struct pte *pen = &ptes[n];
2449 ext_index = n;
2450 pen->ext_pointer = p;
2451 pe4->offset_from_dev_start = extended_offset = start;
2452 pe4->sectorbuffer = xzalloc(sector_size);
2453 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2454 pe4->ext_pointer = pe4->part_table + 1;
2455 pe4->changed = 1;
2456 g_partitions = 5;
2460 static void
2461 add_logical(void)
2463 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2464 struct pte *pe = &ptes[g_partitions];
2466 pe->sectorbuffer = xzalloc(sector_size);
2467 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2468 pe->ext_pointer = pe->part_table + 1;
2469 pe->offset_from_dev_start = 0;
2470 pe->changed = 1;
2471 g_partitions++;
2473 add_partition(g_partitions - 1, LINUX_NATIVE);
2476 static void
2477 new_partition(void)
2479 int i, free_primary = 0;
2481 if (warn_geometry())
2482 return;
2484 if (LABEL_IS_SUN) {
2485 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2486 return;
2488 if (LABEL_IS_SGI) {
2489 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2490 return;
2492 if (LABEL_IS_AIX) {
2493 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2494 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2495 "table first (use 'o'). This will destroy the present disk contents.\n");
2496 return;
2499 for (i = 0; i < 4; i++)
2500 free_primary += !ptes[i].part_table->sys_ind;
2502 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2503 printf("The maximum number of partitions has been created\n");
2504 return;
2507 if (!free_primary) {
2508 if (extended_offset)
2509 add_logical();
2510 else
2511 printf("You must delete some partition and add "
2512 "an extended partition first\n");
2513 } else {
2514 char c, line[80];
2515 snprintf(line, sizeof(line),
2516 "Command action\n"
2517 " %s\n"
2518 " p primary partition (1-4)\n",
2519 (extended_offset ?
2520 "l logical (5 or over)" : "e extended"));
2521 while (1) {
2522 c = read_nonempty(line);
2523 if ((c | 0x20) == 'p') {
2524 i = get_nonexisting_partition(0, 4);
2525 if (i >= 0)
2526 add_partition(i, LINUX_NATIVE);
2527 return;
2529 if (c == 'l' && extended_offset) {
2530 add_logical();
2531 return;
2533 if (c == 'e' && !extended_offset) {
2534 i = get_nonexisting_partition(0, 4);
2535 if (i >= 0)
2536 add_partition(i, EXTENDED);
2537 return;
2539 printf("Invalid partition number "
2540 "for type '%c'\n", c);
2545 static void
2546 reread_partition_table(int leave)
2548 int i;
2550 printf("Calling ioctl() to re-read partition table\n");
2551 sync();
2552 /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
2553 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
2555 sleep(1);
2556 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2557 "WARNING: rereading partition table "
2558 "failed, kernel still uses old table");
2559 #if 0
2560 if (dos_changed)
2561 printf(
2562 "\nWARNING: If you have created or modified any DOS 6.x\n"
2563 "partitions, please see the fdisk manual page for additional\n"
2564 "information\n");
2565 #endif
2567 if (leave) {
2568 if (ENABLE_FEATURE_CLEAN_UP)
2569 close_dev_fd();
2570 exit(i != 0);
2574 static void
2575 write_table(void)
2577 int i;
2579 if (LABEL_IS_DOS) {
2580 for (i = 0; i < 3; i++)
2581 if (ptes[i].changed)
2582 ptes[3].changed = 1;
2583 for (i = 3; i < g_partitions; i++) {
2584 struct pte *pe = &ptes[i];
2585 if (pe->changed) {
2586 write_part_table_flag(pe->sectorbuffer);
2587 write_sector(pe->offset_from_dev_start, pe->sectorbuffer);
2591 else if (LABEL_IS_SGI) {
2592 /* no test on change? the printf below might be mistaken */
2593 sgi_write_table();
2595 else if (LABEL_IS_SUN) {
2596 for (i = 0; i < 8; i++) {
2597 if (ptes[i].changed) {
2598 sun_write_table();
2599 break;
2604 printf("The partition table has been altered.\n");
2605 reread_partition_table(1);
2607 #endif /* FEATURE_FDISK_WRITABLE */
2609 #if ENABLE_FEATURE_FDISK_ADVANCED
2610 #define MAX_PER_LINE 16
2611 static void
2612 print_buffer(char *pbuffer)
2614 int i,l;
2616 for (i = 0, l = 0; i < sector_size; i++, l++) {
2617 if (l == 0)
2618 printf("0x%03X:", i);
2619 printf(" %02X", (unsigned char) pbuffer[i]);
2620 if (l == MAX_PER_LINE - 1) {
2621 bb_putchar('\n');
2622 l = -1;
2625 if (l > 0)
2626 bb_putchar('\n');
2627 bb_putchar('\n');
2630 static void
2631 print_raw(void)
2633 int i;
2635 printf("Device: %s\n", disk_device);
2636 if (LABEL_IS_SGI || LABEL_IS_SUN)
2637 print_buffer(MBRbuffer);
2638 else {
2639 for (i = 3; i < g_partitions; i++)
2640 print_buffer(ptes[i].sectorbuffer);
2644 static void
2645 move_begin(unsigned i)
2647 struct pte *pe = &ptes[i];
2648 struct partition *p = pe->part_table;
2649 sector_t new, first, nr_sects;
2651 if (warn_geometry())
2652 return;
2653 nr_sects = get_nr_sects(p);
2654 if (!p->sys_ind || !nr_sects || IS_EXTENDED(p->sys_ind)) {
2655 printf("Partition %u has no data area\n", i + 1);
2656 return;
2658 first = get_partition_start_from_dev_start(pe); /* == pe->offset_from_dev_start + get_start_sect(p) */
2659 new = read_int(0 /*was:first*/, first, first + nr_sects - 1, first, "New beginning of data");
2660 if (new != first) {
2661 sector_t new_relative = new - pe->offset_from_dev_start;
2662 nr_sects += (get_start_sect(p) - new_relative);
2663 set_start_sect(p, new_relative);
2664 set_nr_sects(p, nr_sects);
2665 read_nonempty("Recalculate C/H/S values? (Y/N): ");
2666 if ((line_ptr[0] | 0x20) == 'y')
2667 set_hsc_start_end(p, new, new + nr_sects - 1);
2668 pe->changed = 1;
2672 static void
2673 xselect(void)
2675 char c;
2677 while (1) {
2678 bb_putchar('\n');
2679 c = 0x20 | read_nonempty("Expert command (m for help): ");
2680 switch (c) {
2681 case 'a':
2682 if (LABEL_IS_SUN)
2683 sun_set_alt_cyl();
2684 break;
2685 case 'b':
2686 if (LABEL_IS_DOS)
2687 move_begin(get_partition(0, g_partitions));
2688 break;
2689 case 'c':
2690 user_cylinders = g_cylinders =
2691 read_int(1, g_cylinders, 1048576, 0,
2692 "Number of cylinders");
2693 if (LABEL_IS_SUN)
2694 sun_set_ncyl(g_cylinders);
2695 if (LABEL_IS_DOS)
2696 warn_cylinders();
2697 break;
2698 case 'd':
2699 print_raw();
2700 break;
2701 case 'e':
2702 if (LABEL_IS_SGI)
2703 sgi_set_xcyl();
2704 else if (LABEL_IS_SUN)
2705 sun_set_xcyl();
2706 else if (LABEL_IS_DOS)
2707 x_list_table(1);
2708 break;
2709 case 'f':
2710 if (LABEL_IS_DOS)
2711 fix_partition_table_order();
2712 break;
2713 case 'g':
2714 #if ENABLE_FEATURE_SGI_LABEL
2715 create_sgilabel();
2716 #endif
2717 break;
2718 case 'h':
2719 user_heads = g_heads = read_int(1, g_heads, 256, 0, "Number of heads");
2720 update_units();
2721 break;
2722 case 'i':
2723 if (LABEL_IS_SUN)
2724 sun_set_ilfact();
2725 break;
2726 case 'o':
2727 if (LABEL_IS_SUN)
2728 sun_set_rspeed();
2729 break;
2730 case 'p':
2731 if (LABEL_IS_SUN)
2732 list_table(1);
2733 else
2734 x_list_table(0);
2735 break;
2736 case 'q':
2737 if (ENABLE_FEATURE_CLEAN_UP)
2738 close_dev_fd();
2739 bb_putchar('\n');
2740 exit(EXIT_SUCCESS);
2741 case 'r':
2742 return;
2743 case 's':
2744 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors");
2745 if (dos_compatible_flag) {
2746 sector_offset = g_sectors;
2747 printf("Warning: setting sector offset for DOS "
2748 "compatiblity\n");
2750 update_units();
2751 break;
2752 case 'v':
2753 verify();
2754 break;
2755 case 'w':
2756 write_table(); /* does not return */
2757 break;
2758 case 'y':
2759 if (LABEL_IS_SUN)
2760 sun_set_pcylcount();
2761 break;
2762 default:
2763 xmenu();
2767 #endif /* ADVANCED mode */
2769 static int
2770 is_ide_cdrom_or_tape(const char *device)
2772 FILE *procf;
2773 char buf[100];
2774 struct stat statbuf;
2775 int is_ide = 0;
2777 /* No device was given explicitly, and we are trying some
2778 likely things. But opening /dev/hdc may produce errors like
2779 "hdc: tray open or drive not ready"
2780 if it happens to be a CD-ROM drive. It even happens that
2781 the process hangs on the attempt to read a music CD.
2782 So try to be careful. This only works since 2.1.73. */
2784 if (strncmp("/dev/hd", device, 7))
2785 return 0;
2787 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2788 procf = fopen_for_read(buf);
2789 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2790 is_ide = (!strncmp(buf, "cdrom", 5) ||
2791 !strncmp(buf, "tape", 4));
2792 else
2793 /* Now when this proc file does not exist, skip the
2794 device when it is read-only. */
2795 if (stat(device, &statbuf) == 0)
2796 is_ide = ((statbuf.st_mode & 0222) == 0);
2798 if (procf)
2799 fclose(procf);
2800 return is_ide;
2804 static void
2805 open_list_and_close(const char *device, int user_specified)
2807 int gb;
2809 disk_device = device;
2810 if (setjmp(listingbuf))
2811 return;
2812 if (!user_specified)
2813 if (is_ide_cdrom_or_tape(device))
2814 return;
2816 /* Open disk_device, save file descriptor to dev_fd */
2817 errno = 0;
2818 gb = get_boot(TRY_ONLY);
2819 if (gb > 0) { /* I/O error */
2820 /* Ignore other errors, since we try IDE
2821 and SCSI hard disks which may not be
2822 installed on the system. */
2823 if (user_specified || errno == EACCES)
2824 bb_perror_msg("can't open '%s'", device);
2825 return;
2828 if (gb < 0) { /* no DOS signature */
2829 list_disk_geometry();
2830 if (LABEL_IS_AIX)
2831 goto ret;
2832 #if ENABLE_FEATURE_OSF_LABEL
2833 if (bsd_trydev(device) < 0)
2834 #endif
2835 printf("Disk %s doesn't contain a valid "
2836 "partition table\n", device);
2837 } else {
2838 list_table(0);
2839 #if ENABLE_FEATURE_FDISK_WRITABLE
2840 if (!LABEL_IS_SUN && g_partitions > 4) {
2841 delete_partition(ext_index);
2843 #endif
2845 ret:
2846 close_dev_fd();
2849 /* Is it a whole disk? The digit check is still useful
2850 for Xen devices for example. */
2851 static int is_whole_disk(const char *disk)
2853 unsigned len;
2854 int fd = open(disk, O_RDONLY);
2856 if (fd != -1) {
2857 struct hd_geometry geometry;
2858 int err = ioctl(fd, HDIO_GETGEO, &geometry);
2859 close(fd);
2860 if (!err)
2861 return (geometry.start == 0);
2864 /* Treat "nameN" as a partition name, not whole disk */
2865 /* note: mmcblk0 should work from the geometry check above */
2866 len = strlen(disk);
2867 if (len != 0 && isdigit(disk[len - 1]))
2868 return 0;
2870 return 1;
2873 /* for fdisk -l: try all things in /proc/partitions
2874 that look like a partition name (do not end in a digit) */
2875 static void
2876 list_devs_in_proc_partititons(void)
2878 FILE *procpt;
2879 char line[100], ptname[100], devname[120];
2880 int ma, mi, sz;
2882 procpt = fopen_or_warn("/proc/partitions", "r");
2884 while (fgets(line, sizeof(line), procpt)) {
2885 if (sscanf(line, " %u %u %u %[^\n ]",
2886 &ma, &mi, &sz, ptname) != 4)
2887 continue;
2889 sprintf(devname, "/dev/%s", ptname);
2890 if (is_whole_disk(devname))
2891 open_list_and_close(devname, 0);
2893 #if ENABLE_FEATURE_CLEAN_UP
2894 fclose(procpt);
2895 #endif
2898 #if ENABLE_FEATURE_FDISK_WRITABLE
2899 static void
2900 unknown_command(int c)
2902 printf("%c: unknown command\n", c);
2904 #endif
2906 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2907 int fdisk_main(int argc UNUSED_PARAM, char **argv)
2909 unsigned opt;
2911 * fdisk -v
2912 * fdisk -l [-b sectorsize] [-u] device ...
2913 * fdisk -s [partition] ...
2914 * fdisk [-b sectorsize] [-u] device
2916 * Options -C, -H, -S set the geometry.
2918 INIT_G();
2920 close_dev_fd(); /* needed: fd 3 must not stay closed */
2922 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2923 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2924 &sector_size, &user_cylinders, &user_heads, &user_sectors);
2925 argv += optind;
2926 if (opt & OPT_b) {
2927 /* Ugly: this sector size is really per device,
2928 * so cannot be combined with multiple disks,
2929 * and the same goes for the C/H/S options.
2931 if (sector_size < 512
2932 || sector_size > 0x10000
2933 || (sector_size & (sector_size-1)) /* not power of 2 */
2935 bb_show_usage();
2937 sector_offset = 2;
2938 user_set_sector_size = 1;
2940 if (user_heads <= 0 || user_heads >= 256)
2941 user_heads = 0;
2942 if (user_sectors <= 0 || user_sectors >= 64)
2943 user_sectors = 0;
2944 if (opt & OPT_u)
2945 display_in_cyl_units = 0; // -u
2947 #if ENABLE_FEATURE_FDISK_WRITABLE
2948 if (opt & OPT_l) {
2949 nowarn = 1;
2950 #endif
2951 if (*argv) {
2952 listing = 1;
2953 do {
2954 open_list_and_close(*argv, 1);
2955 } while (*++argv);
2956 } else {
2957 /* we don't have device names, */
2958 /* use /proc/partitions instead */
2959 list_devs_in_proc_partititons();
2961 return 0;
2962 #if ENABLE_FEATURE_FDISK_WRITABLE
2964 #endif
2966 #if ENABLE_FEATURE_FDISK_BLKSIZE
2967 if (opt & OPT_s) {
2968 int j;
2970 nowarn = 1;
2971 if (!argv[0])
2972 bb_show_usage();
2973 for (j = 0; argv[j]; j++) {
2974 unsigned long long size;
2975 fd = xopen(argv[j], O_RDONLY);
2976 size = bb_BLKGETSIZE_sectors(fd) / 2;
2977 close(fd);
2978 if (argv[1])
2979 printf("%llu\n", size);
2980 else
2981 printf("%s: %llu\n", argv[j], size);
2983 return 0;
2985 #endif
2987 #if ENABLE_FEATURE_FDISK_WRITABLE
2988 if (!argv[0] || argv[1])
2989 bb_show_usage();
2991 disk_device = argv[0];
2992 get_boot(OPEN_MAIN);
2994 if (LABEL_IS_OSF) {
2995 /* OSF label, and no DOS label */
2996 printf("Detected an OSF/1 disklabel on %s, entering "
2997 "disklabel mode\n", disk_device);
2998 bsd_select();
2999 /*Why do we do this? It seems to be counter-intuitive*/
3000 current_label_type = LABEL_DOS;
3001 /* If we return we may want to make an empty DOS label? */
3004 while (1) {
3005 int c;
3006 bb_putchar('\n');
3007 c = 0x20 | read_nonempty("Command (m for help): ");
3008 switch (c) {
3009 case 'a':
3010 if (LABEL_IS_DOS)
3011 toggle_active(get_partition(1, g_partitions));
3012 else if (LABEL_IS_SUN)
3013 toggle_sunflags(get_partition(1, g_partitions),
3014 0x01);
3015 else if (LABEL_IS_SGI)
3016 sgi_set_bootpartition(
3017 get_partition(1, g_partitions));
3018 else
3019 unknown_command(c);
3020 break;
3021 case 'b':
3022 if (LABEL_IS_SGI) {
3023 printf("\nThe current boot file is: %s\n",
3024 sgi_get_bootfile());
3025 if (read_maybe_empty("Please enter the name of the "
3026 "new boot file: ") == '\n')
3027 printf("Boot file unchanged\n");
3028 else
3029 sgi_set_bootfile(line_ptr);
3031 #if ENABLE_FEATURE_OSF_LABEL
3032 else
3033 bsd_select();
3034 #endif
3035 break;
3036 case 'c':
3037 if (LABEL_IS_DOS)
3038 toggle_dos_compatibility_flag();
3039 else if (LABEL_IS_SUN)
3040 toggle_sunflags(get_partition(1, g_partitions),
3041 0x10);
3042 else if (LABEL_IS_SGI)
3043 sgi_set_swappartition(
3044 get_partition(1, g_partitions));
3045 else
3046 unknown_command(c);
3047 break;
3048 case 'd':
3050 int j;
3051 /* If sgi_label then don't use get_existing_partition,
3052 let the user select a partition, since
3053 get_existing_partition() only works for Linux-like
3054 partition tables */
3055 if (!LABEL_IS_SGI) {
3056 j = get_existing_partition(1, g_partitions);
3057 } else {
3058 j = get_partition(1, g_partitions);
3060 if (j >= 0)
3061 delete_partition(j);
3063 break;
3064 case 'i':
3065 if (LABEL_IS_SGI)
3066 create_sgiinfo();
3067 else
3068 unknown_command(c);
3069 case 'l':
3070 list_types(get_sys_types());
3071 break;
3072 case 'm':
3073 menu();
3074 break;
3075 case 'n':
3076 new_partition();
3077 break;
3078 case 'o':
3079 create_doslabel();
3080 break;
3081 case 'p':
3082 list_table(0);
3083 break;
3084 case 'q':
3085 if (ENABLE_FEATURE_CLEAN_UP)
3086 close_dev_fd();
3087 bb_putchar('\n');
3088 return 0;
3089 case 's':
3090 #if ENABLE_FEATURE_SUN_LABEL
3091 create_sunlabel();
3092 #endif
3093 break;
3094 case 't':
3095 change_sysid();
3096 break;
3097 case 'u':
3098 change_units();
3099 break;
3100 case 'v':
3101 verify();
3102 break;
3103 case 'w':
3104 write_table(); /* does not return */
3105 break;
3106 #if ENABLE_FEATURE_FDISK_ADVANCED
3107 case 'x':
3108 if (LABEL_IS_SGI) {
3109 printf("\n\tSorry, no experts menu for SGI "
3110 "partition tables available\n\n");
3111 } else
3112 xselect();
3113 break;
3114 #endif
3115 default:
3116 unknown_command(c);
3117 menu();
3120 return 0;
3121 #endif /* FEATURE_FDISK_WRITABLE */