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