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