source: MondoRescue/branches/3.3/mindi-busybox/util-linux/fdisk.c@ 3621

Last change on this file since 3621 was 3621, checked in by Bruno Cornec, 7 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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