source: MondoRescue/branches/stable/mindi-busybox/util-linux/fdisk.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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