Magellan Linux

Contents of /tags/mkinitrd-6_4_0/busybox/util-linux/fdisk.c

Parent Directory Parent Directory | Revision Log Revision Log


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