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, 12 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.