lots of silly indent fixes
[platform/upstream/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 /* Current changes have not compatibility with this version */
11 #define UTIL_LINUX_VERSION "2.12"
12
13
14 #define _(x) x
15
16 #define PROC_PARTITIONS "/proc/partitions"
17
18 #include <features.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>           /* stat */
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <setjmp.h>
29 #include <assert.h>             /* assert */
30 #include <getopt.h>
31 #include <endian.h>
32 #include <sys/ioctl.h>
33 #include <sys/param.h>
34 #include <sys/sysmacros.h>     /* major */
35
36 #include <stdint.h>        /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
37
38 /* Copied from linux/major.h */
39 #define FLOPPY_MAJOR    2
40
41 #include <sys/utsname.h>
42
43 #include "busybox.h"
44
45 #define DKTYPENAMES
46
47 /*
48    fdisk.h
49 */
50
51 #define DEFAULT_SECTOR_SIZE     512
52 #define MAX_SECTOR_SIZE 2048
53 #define SECTOR_SIZE     512     /* still used in BSD code */
54 #define MAXIMUM_PARTS   60
55
56 #define ACTIVE_FLAG     0x80
57
58 #define EXTENDED        0x05
59 #define WIN98_EXTENDED  0x0f
60 #define LINUX_PARTITION 0x81
61 #define LINUX_SWAP      0x82
62 #define LINUX_NATIVE    0x83
63 #define LINUX_EXTENDED  0x85
64 #define LINUX_LVM       0x8e
65 #define LINUX_RAID      0xfd
66
67 #define SUNOS_SWAP 3
68 #define WHOLE_DISK 5
69
70 #define IS_EXTENDED(i) \
71         ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
72
73 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
74
75 #define cround(n)       (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
76 #define scround(x)      (((x)+units_per_sector-1)/units_per_sector)
77
78 #ifdef CONFIG_FEATURE_SUN_LABEL
79 #define SCSI_IOCTL_GET_IDLUN 0x5382
80 #endif
81
82
83 /* including <linux/hdreg.h> also fails */
84 struct hd_geometry {
85         unsigned char heads;
86         unsigned char sectors;
87         unsigned short cylinders;
88         unsigned long start;
89 };
90
91 #define HDIO_GETGEO             0x0301  /* get device geometry */
92
93
94 struct systypes {
95         const char *name;
96 };
97
98 static uint sector_size = DEFAULT_SECTOR_SIZE;
99 static uint user_set_sector_size;
100 static uint sector_offset = 1;
101
102 /*
103  * Raw disk label. For DOS-type partition tables the MBR,
104  * with descriptions of the primary partitions.
105  */
106 #if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
107 static char MBRbuffer[MAX_SECTOR_SIZE];
108 #else
109 # define MBRbuffer bb_common_bufsiz1
110 #endif
111
112 #ifdef CONFIG_FEATURE_OSF_LABEL
113 static int possibly_osf_label;
114 #endif
115
116 static uint heads, sectors, cylinders;
117 static void update_units(void);
118
119
120 /*
121  * return partition name - uses static storage unless buf is supplied
122  */
123 static const char *
124 partname(const char *dev, int pno, int lth)
125 {
126         static char buffer[80];
127         const char *p;
128         int w, wp;
129         int bufsiz;
130         char *bufp;
131
132         bufp = buffer;
133         bufsiz = sizeof(buffer);
134
135         w = strlen(dev);
136         p = "";
137
138         if (isdigit(dev[w-1]))
139                 p = "p";
140
141         /* devfs kludge - note: fdisk partition names are not supposed
142            to equal kernel names, so there is no reason to do this */
143         if (strcmp(dev + w - 4, "disc") == 0) {
144                 w -= 4;
145                 p = "part";
146         }
147
148         wp = strlen(p);
149
150         if (lth) {
151                 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
152                          lth-wp-2, w, dev, p, pno);
153         } else {
154                 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
155         }
156         return bufp;
157 }
158
159 struct partition {
160         unsigned char boot_ind;         /* 0x80 - active */
161         unsigned char head;             /* starting head */
162         unsigned char sector;           /* starting sector */
163         unsigned char cyl;              /* starting cylinder */
164         unsigned char sys_ind;          /* What partition type */
165         unsigned char end_head;         /* end head */
166         unsigned char end_sector;       /* end sector */
167         unsigned char end_cyl;          /* end cylinder */
168         unsigned char start4[4];        /* starting sector counting from 0 */
169         unsigned char size4[4];         /* nr of sectors in partition */
170 } ATTRIBUTE_PACKED;
171
172 enum failure {
173         ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
174         unable_to_write
175 };
176
177 enum label_type{
178         label_dos, label_sun, label_sgi, label_aix, label_osf
179 };
180
181 enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
182
183 static enum label_type current_label_type;
184
185 static const char *disk_device;
186 static int fd;                  /* the disk */
187 static int partitions = 4;      /* maximum partition + 1 */
188 static uint display_in_cyl_units = 1;
189 static uint units_per_sector = 1;
190 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
191 static char *line_ptr;
192 static void change_units(void);
193 static void reread_partition_table(int leave);
194 static void delete_partition(int i);
195 static int get_partition(int warn, int max);
196 static void list_types(const struct systypes *sys);
197 static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
198 #endif
199 static const char *partition_type(unsigned char type);
200 static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
201 static void get_geometry(void);
202 static int get_boot(enum action what);
203
204 #define PLURAL   0
205 #define SINGULAR 1
206
207 #define hex_val(c)      ({ \
208                                 char _c = (c); \
209                                 isdigit(_c) ? _c - '0' : \
210                                 tolower(_c) + 10 - 'a'; \
211                         })
212
213
214 #define LINE_LENGTH     800
215 #define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
216                                 (n) * sizeof(struct partition)))
217 #define sector(s)       ((s) & 0x3f)
218 #define cylinder(s, c)  ((c) | (((s) & 0xc0) << 2))
219
220 #define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
221                                 ((h) + heads * cylinder(s,c)))
222 #define set_hsc(h,s,c,sector) { \
223                                 s = sector % sectors + 1;       \
224                                 sector /= sectors;      \
225                                 h = sector % heads;     \
226                                 sector /= heads;        \
227                                 c = sector & 0xff;      \
228                                 s |= (sector >> 2) & 0xc0;      \
229                         }
230
231
232 static int32_t get_start_sect(const struct partition *p);
233 static int32_t get_nr_sects(const struct partition *p);
234
235 /*
236  * per partition table entry data
237  *
238  * The four primary partitions have the same sectorbuffer (MBRbuffer)
239  * and have NULL ext_pointer.
240  * Each logical partition table entry has two pointers, one for the
241  * partition and one link to the next one.
242  */
243 static struct pte {
244         struct partition *part_table;   /* points into sectorbuffer */
245         struct partition *ext_pointer;  /* points into sectorbuffer */
246 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
247         char changed;           /* boolean */
248 #endif
249         off_t offset;            /* disk sector number */
250         char *sectorbuffer;     /* disk sector contents */
251 } ptes[MAXIMUM_PARTS];
252
253
254 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
255 static void
256 set_all_unchanged(void)
257 {
258         int i;
259
260         for (i = 0; i < MAXIMUM_PARTS; i++)
261                 ptes[i].changed = 0;
262 }
263
264 static void
265 set_changed(int i)
266 {
267         ptes[i].changed = 1;
268 }
269 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
270
271 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
272 static struct partition *
273 get_part_table(int i)
274 {
275         return ptes[i].part_table;
276 }
277 #endif
278
279 static const char *
280 str_units(int n)
281 {      /* n==1: use singular */
282         if (n == 1)
283                 return display_in_cyl_units ? _("cylinder") : _("sector");
284         else
285                 return display_in_cyl_units ? _("cylinders") : _("sectors");
286 }
287
288 static int
289 valid_part_table_flag(const char *mbuffer) {
290         const unsigned char *b = (const unsigned char *)mbuffer;
291         return (b[510] == 0x55 && b[511] == 0xaa);
292 }
293
294 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
295 static char  line_buffer[LINE_LENGTH];
296
297 /* read line; return 0 or first char */
298 static int
299 read_line(void)
300 {
301         static int got_eof = 0;
302
303         fflush (stdout);         /* requested by niles@scyld.com */
304         line_ptr = line_buffer;
305         if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
306                 if (feof(stdin))
307                         got_eof++;      /* user typed ^D ? */
308                 if (got_eof >= 3) {
309                         fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
310                         exit(1);
311                 }
312                 return 0;
313         }
314         while (*line_ptr && !isgraph(*line_ptr))
315                 line_ptr++;
316         return *line_ptr;
317 }
318
319 static char
320 read_char(const char *mesg)
321 {
322         do {
323                 fputs(mesg, stdout);
324         } while (!read_line());
325         return *line_ptr;
326 }
327
328 static char
329 read_chars(const char *mesg)
330 {
331         fputs(mesg, stdout);
332         if (!read_line()) {
333                 *line_ptr = '\n';
334                 line_ptr[1] = 0;
335         }
336         return *line_ptr;
337 }
338
339 static int
340 read_hex(const struct systypes *sys)
341 {
342         int hex;
343
344         while (1) {
345                 read_char(_("Hex code (type L to list codes): "));
346                 if (*line_ptr == 'l' || *line_ptr == 'L')
347                         list_types(sys);
348                 else if (isxdigit (*line_ptr)) {
349                         hex = 0;
350                         do
351                                 hex = hex << 4 | hex_val(*line_ptr++);
352                         while (isxdigit(*line_ptr));
353                         return hex;
354                 }
355         }
356 }
357 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
358
359 #ifdef CONFIG_FEATURE_AIX_LABEL
360 /*
361  * Copyright (C) Andreas Neuper, Sep 1998.
362  *      This file may be redistributed under
363  *      the terms of the GNU Public License.
364  */
365
366 typedef struct {
367         unsigned int   magic;        /* expect AIX_LABEL_MAGIC */
368         unsigned int   fillbytes1[124];
369         unsigned int   physical_volume_id;
370         unsigned int   fillbytes2[124];
371 } aix_partition;
372
373 #define AIX_LABEL_MAGIC         0xc9c2d4c1
374 #define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
375 #define AIX_INFO_MAGIC          0x00072959
376 #define AIX_INFO_MAGIC_SWAPPED  0x59290700
377
378 #define aixlabel ((aix_partition *)MBRbuffer)
379
380
381 /*
382   Changes:
383   * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
384   *     Internationalization
385   *
386   * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
387   *      Some fixes
388 */
389
390 static int aix_other_endian;
391 static short aix_volumes = 1;
392
393 /*
394  * only dealing with free blocks here
395  */
396
397 static void
398 aix_info(void)
399 {
400         puts(
401                 _("\n\tThere is a valid AIX label on this disk.\n"
402                 "\tUnfortunately Linux cannot handle these\n"
403                 "\tdisks at the moment.  Nevertheless some\n"
404                 "\tadvice:\n"
405                 "\t1. fdisk will destroy its contents on write.\n"
406                 "\t2. Be sure that this disk is NOT a still vital\n"
407                 "\t   part of a volume group. (Otherwise you may\n"
408                 "\t   erase the other disks as well, if unmirrored.)\n"
409                 "\t3. Before deleting this physical volume be sure\n"
410                 "\t   to remove the disk logically from your AIX\n"
411                 "\t   machine.  (Otherwise you become an AIXpert).")
412         );
413 }
414
415 static int
416 check_aix_label(void)
417 {
418         if (aixlabel->magic != AIX_LABEL_MAGIC &&
419                 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
420                 current_label_type = 0;
421                 aix_other_endian = 0;
422                 return 0;
423         }
424         aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
425         update_units();
426         current_label_type = label_aix;
427         partitions = 1016;
428         aix_volumes = 15;
429         aix_info();
430         /*aix_nolabel();*/              /* %% */
431         /*aix_label = 1;*/              /* %% */
432         return 1;
433 }
434 #endif  /* AIX_LABEL */
435
436 #ifdef CONFIG_FEATURE_OSF_LABEL
437 /*
438  * Copyright (c) 1987, 1988 Regents of the University of California.
439  * All rights reserved.
440  *
441  * Redistribution and use in source and binary forms, with or without
442  * modification, are permitted provided that the following conditions
443  * are met:
444  * 1. Redistributions of source code must retain the above copyright
445  *    notice, this list of conditions and the following disclaimer.
446  * 2. Redistributions in binary form must reproduce the above copyright
447  *    notice, this list of conditions and the following disclaimer in the
448  *    documentation and/or other materials provided with the distribution.
449  * 3. All advertising materials mentioning features or use of this software
450  *    must display the following acknowledgment:
451  *      This product includes software developed by the University of
452  *      California, Berkeley and its contributors.
453  * 4. Neither the name of the University nor the names of its contributors
454  *    may be used to endorse or promote products derived from this software
455  *    without specific prior written permission.
456  *
457  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
458  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
459  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
460  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
461  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
462  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
463  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
464  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
465  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
466  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
467  * SUCH DAMAGE.
468  */
469
470
471 #ifndef BSD_DISKMAGIC
472 #define BSD_DISKMAGIC     ((uint32_t) 0x82564557)
473 #endif
474
475 #ifndef BSD_MAXPARTITIONS
476 #define BSD_MAXPARTITIONS 16
477 #endif
478
479 #define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
480
481 #if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__m68k__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
482 #define BSD_LABELSECTOR   1
483 #define BSD_LABELOFFSET   0
484 #elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
485 #define BSD_LABELSECTOR   0
486 #define BSD_LABELOFFSET   64
487 #elif defined (__s390__) || defined (__s390x__)
488 #define BSD_LABELSECTOR   1
489 #define BSD_LABELOFFSET   0
490 #else
491 #error unknown architecture
492 #endif
493
494 #define BSD_BBSIZE        8192          /* size of boot area, with label */
495 #define BSD_SBSIZE        8192          /* max size of fs superblock */
496
497 struct xbsd_disklabel {
498         uint32_t   d_magic;                /* the magic number */
499         int16_t    d_type;                 /* drive type */
500         int16_t    d_subtype;              /* controller/d_type specific */
501         char       d_typename[16];         /* type name, e.g. "eagle" */
502         char       d_packname[16];                 /* pack identifier */
503                         /* disk geometry: */
504         uint32_t   d_secsize;              /* # of bytes per sector */
505         uint32_t   d_nsectors;             /* # of data sectors per track */
506         uint32_t   d_ntracks;              /* # of tracks per cylinder */
507         uint32_t   d_ncylinders;           /* # of data cylinders per unit */
508         uint32_t   d_secpercyl;            /* # of data sectors per cylinder */
509         uint32_t   d_secperunit;           /* # of data sectors per unit */
510         /*
511          * Spares (bad sector replacements) below
512          * are not counted in d_nsectors or d_secpercyl.
513          * Spare sectors are assumed to be physical sectors
514          * which occupy space at the end of each track and/or cylinder.
515          */
516         uint16_t   d_sparespertrack;       /* # of spare sectors per track */
517         uint16_t   d_sparespercyl;         /* # of spare sectors per cylinder */
518         /*
519          * Alternate cylinders include maintenance, replacement,
520          * configuration description areas, etc.
521          */
522         uint32_t   d_acylinders;           /* # of alt. cylinders per unit */
523
524                         /* hardware characteristics: */
525         /*
526          * d_interleave, d_trackskew and d_cylskew describe perturbations
527          * in the media format used to compensate for a slow controller.
528          * Interleave is physical sector interleave, set up by the formatter
529          * or controller when formatting.  When interleaving is in use,
530          * logically adjacent sectors are not physically contiguous,
531          * but instead are separated by some number of sectors.
532          * It is specified as the ratio of physical sectors traversed
533          * per logical sector.  Thus an interleave of 1:1 implies contiguous
534          * layout, while 2:1 implies that logical sector 0 is separated
535          * by one sector from logical sector 1.
536          * d_trackskew is the offset of sector 0 on track N
537          * relative to sector 0 on track N-1 on the same cylinder.
538          * Finally, d_cylskew is the offset of sector 0 on cylinder N
539          * relative to sector 0 on cylinder N-1.
540          */
541         uint16_t   d_rpm;                  /* rotational speed */
542         uint16_t   d_interleave;           /* hardware sector interleave */
543         uint16_t   d_trackskew;            /* sector 0 skew, per track */
544         uint16_t   d_cylskew;              /* sector 0 skew, per cylinder */
545         uint32_t   d_headswitch;           /* head switch time, usec */
546         uint32_t   d_trkseek;              /* track-to-track seek, usec */
547         uint32_t   d_flags;                /* generic flags */
548 #define NDDATA 5
549         uint32_t   d_drivedata[NDDATA];    /* drive-type specific information */
550 #define NSPARE 5
551         uint32_t   d_spare[NSPARE];        /* reserved for future use */
552         uint32_t   d_magic2;               /* the magic number (again) */
553         uint16_t   d_checksum;             /* xor of data incl. partitions */
554                         /* filesystem and partition information: */
555         uint16_t   d_npartitions;          /* number of partitions in following */
556         uint32_t   d_bbsize;               /* size of boot area at sn0, bytes */
557         uint32_t   d_sbsize;               /* max size of fs superblock, bytes */
558         struct xbsd_partition    {      /* the partition table */
559                 uint32_t   p_size;         /* number of sectors in partition */
560                 uint32_t   p_offset;       /* starting sector */
561                 uint32_t   p_fsize;        /* filesystem basic fragment size */
562                 uint8_t    p_fstype;       /* filesystem type, see below */
563                 uint8_t    p_frag;         /* filesystem fragments per block */
564                 uint16_t   p_cpg;          /* filesystem cylinders per group */
565         } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
566 };
567
568 /* d_type values: */
569 #define BSD_DTYPE_SMD           1               /* SMD, XSMD; VAX hp/up */
570 #define BSD_DTYPE_MSCP          2               /* MSCP */
571 #define BSD_DTYPE_DEC           3               /* other DEC (rk, rl) */
572 #define BSD_DTYPE_SCSI          4               /* SCSI */
573 #define BSD_DTYPE_ESDI          5               /* ESDI interface */
574 #define BSD_DTYPE_ST506         6               /* ST506 etc. */
575 #define BSD_DTYPE_HPIB          7               /* CS/80 on HP-IB */
576 #define BSD_DTYPE_HPFL          8               /* HP Fiber-link */
577 #define BSD_DTYPE_FLOPPY        10              /* floppy */
578
579 /* d_subtype values: */
580 #define BSD_DSTYPE_INDOSPART    0x8             /* is inside dos partition */
581 #define BSD_DSTYPE_DOSPART(s)   ((s) & 3)       /* dos partition number */
582 #define BSD_DSTYPE_GEOMETRY     0x10            /* drive params in label */
583
584 #ifdef DKTYPENAMES
585 static const char * const xbsd_dktypenames[] = {
586         "unknown",
587         "SMD",
588         "MSCP",
589         "old DEC",
590         "SCSI",
591         "ESDI",
592         "ST506",
593         "HP-IB",
594         "HP-FL",
595         "type 9",
596         "floppy",
597         0
598 };
599 #define BSD_DKMAXTYPES  (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
600 #endif
601
602 /*
603  * Filesystem type and version.
604  * Used to interpret other filesystem-specific
605  * per-partition information.
606  */
607 #define BSD_FS_UNUSED   0               /* unused */
608 #define BSD_FS_SWAP     1               /* swap */
609 #define BSD_FS_V6       2               /* Sixth Edition */
610 #define BSD_FS_V7       3               /* Seventh Edition */
611 #define BSD_FS_SYSV     4               /* System V */
612 #define BSD_FS_V71K     5               /* V7 with 1K blocks (4.1, 2.9) */
613 #define BSD_FS_V8       6               /* Eighth Edition, 4K blocks */
614 #define BSD_FS_BSDFFS   7               /* 4.2BSD fast file system */
615 #define BSD_FS_BSDLFS   9               /* 4.4BSD log-structured file system */
616 #define BSD_FS_OTHER    10              /* in use, but unknown/unsupported */
617 #define BSD_FS_HPFS     11              /* OS/2 high-performance file system */
618 #define BSD_FS_ISO9660  12              /* ISO-9660 filesystem (cdrom) */
619 #define BSD_FS_ISOFS    BSD_FS_ISO9660
620 #define BSD_FS_BOOT     13              /* partition contains bootstrap */
621 #define BSD_FS_ADOS     14              /* AmigaDOS fast file system */
622 #define BSD_FS_HFS      15              /* Macintosh HFS */
623 #define BSD_FS_ADVFS    16              /* Digital Unix AdvFS */
624
625 /* this is annoying, but it's also the way it is :-( */
626 #ifdef __alpha__
627 #define BSD_FS_EXT2     8               /* ext2 file system */
628 #else
629 #define BSD_FS_MSDOS    8               /* MS-DOS file system */
630 #endif
631
632 #ifdef  DKTYPENAMES
633 static const struct systypes xbsd_fstypes[] = {
634         { "\x00" "unused" },            /* BSD_FS_UNUSED  */
635         { "\x01" "swap" },              /* BSD_FS_SWAP    */
636         { "\x02" "Version 6" },         /* BSD_FS_V6      */
637         { "\x03" "Version 7" },         /* BSD_FS_V7      */
638         { "\x04" "System V" },          /* BSD_FS_SYSV    */
639         { "\x05" "4.1BSD" },            /* BSD_FS_V71K    */
640         { "\x06" "Eighth Edition" },    /* BSD_FS_V8      */
641         { "\x07" "4.2BSD" },            /* BSD_FS_BSDFFS  */
642 #ifdef __alpha__
643         { "\x08" "ext2" },              /* BSD_FS_EXT2    */
644 #else
645         { "\x08" "MS-DOS" },            /* BSD_FS_MSDOS   */
646 #endif
647         { "\x09" "4.4LFS" },            /* BSD_FS_BSDLFS  */
648         { "\x0a" "unknown" },           /* BSD_FS_OTHER   */
649         { "\x0b" "HPFS" },              /* BSD_FS_HPFS    */
650         { "\x0c" "ISO-9660" },          /* BSD_FS_ISO9660 */
651         { "\x0d" "boot" },              /* BSD_FS_BOOT    */
652         { "\x0e" "ADOS" },              /* BSD_FS_ADOS    */
653         { "\x0f" "HFS" },               /* BSD_FS_HFS     */
654         { "\x10" "AdvFS" },             /* BSD_FS_ADVFS   */
655         { NULL }
656 };
657 #define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
658
659 #endif
660
661 /*
662  * flags shared by various drives:
663  */
664 #define BSD_D_REMOVABLE 0x01            /* removable media */
665 #define BSD_D_ECC       0x02            /* supports ECC */
666 #define BSD_D_BADSECT   0x04            /* supports bad sector forw. */
667 #define BSD_D_RAMDISK   0x08            /* disk emulator */
668 #define BSD_D_CHAIN     0x10            /* can do back-back transfers */
669 #define BSD_D_DOSPART   0x20            /* within MSDOS partition */
670
671 #endif /* OSF_LABEL */
672
673 /*
674  * Copyright (C) Andreas Neuper, Sep 1998.
675  *      This file may be modified and redistributed under
676  *      the terms of the GNU Public License.
677  */
678
679 struct device_parameter { /* 48 bytes */
680         unsigned char  skew;
681         unsigned char  gap1;
682         unsigned char  gap2;
683         unsigned char  sparecyl;
684         unsigned short pcylcount;
685         unsigned short head_vol0;
686         unsigned short ntrks;   /* tracks in cyl 0 or vol 0 */
687         unsigned char  cmd_tag_queue_depth;
688         unsigned char  unused0;
689         unsigned short unused1;
690         unsigned short nsect;   /* sectors/tracks in cyl 0 or vol 0 */
691         unsigned short bytes;
692         unsigned short ilfact;
693         unsigned int   flags;           /* controller flags */
694         unsigned int   datarate;
695         unsigned int   retries_on_error;
696         unsigned int   ms_per_word;
697         unsigned short xylogics_gap1;
698         unsigned short xylogics_syncdelay;
699         unsigned short xylogics_readdelay;
700         unsigned short xylogics_gap2;
701         unsigned short xylogics_readgate;
702         unsigned short xylogics_writecont;
703 };
704
705 #define SGI_VOLHDR      0x00
706 /* 1 and 2 were used for drive types no longer supported by SGI */
707 #define SGI_SWAP        0x03
708 /* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
709 #define SGI_VOLUME      0x06
710 #define SGI_EFS         0x07
711 #define SGI_LVOL        0x08
712 #define SGI_RLVOL       0x09
713 #define SGI_XFS         0x0a
714 #define SGI_XFSLOG      0x0b
715 #define SGI_XLV         0x0c
716 #define SGI_XVM         0x0d
717 #define ENTIRE_DISK     SGI_VOLUME
718 /*
719  * controller flags
720  */
721 #define SECTOR_SLIP     0x01
722 #define SECTOR_FWD      0x02
723 #define TRACK_FWD       0x04
724 #define TRACK_MULTIVOL  0x08
725 #define IGNORE_ERRORS   0x10
726 #define RESEEK          0x20
727 #define ENABLE_CMDTAGQ  0x40
728
729 typedef struct {
730         unsigned int   magic;            /* expect SGI_LABEL_MAGIC */
731         unsigned short boot_part;        /* active boot partition */
732         unsigned short swap_part;        /* active swap partition */
733         unsigned char  boot_file[16];    /* name of the bootfile */
734         struct device_parameter devparam;       /*  1 * 48 bytes */
735         struct volume_directory {               /* 15 * 16 bytes */
736                 unsigned char vol_file_name[8]; /* a character array */
737                 unsigned int  vol_file_start;   /* number of logical block */
738                 unsigned int  vol_file_size;    /* number of bytes */
739         } directory[15];
740         struct sgi_partition {                  /* 16 * 12 bytes */
741                 unsigned int num_sectors;       /* number of blocks */
742                 unsigned int start_sector;      /* must be cylinder aligned */
743                 unsigned int id;
744         } partitions[16];
745         unsigned int   csum;
746         unsigned int   fillbytes;
747 } sgi_partition;
748
749 typedef struct {
750         unsigned int   magic;           /* looks like a magic number */
751         unsigned int   a2;
752         unsigned int   a3;
753         unsigned int   a4;
754         unsigned int   b1;
755         unsigned short b2;
756         unsigned short b3;
757         unsigned int   c[16];
758         unsigned short d[3];
759         unsigned char  scsi_string[50];
760         unsigned char  serial[137];
761         unsigned short check1816;
762         unsigned char  installer[225];
763 } sgiinfo;
764
765 #define SGI_LABEL_MAGIC         0x0be5a941
766 #define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
767 #define SGI_INFO_MAGIC          0x00072959
768 #define SGI_INFO_MAGIC_SWAPPED  0x59290700
769 #define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
770                                  : (uint16_t)(x))
771 #define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
772                                  : (uint32_t)(x))
773
774 #define sgilabel ((sgi_partition *)MBRbuffer)
775 #define sgiparam (sgilabel->devparam)
776
777 typedef struct {
778         unsigned char info[128];   /* Informative text string */
779         unsigned char spare0[14];
780         struct sun_info {
781                 unsigned char spare1;
782                 unsigned char id;
783                 unsigned char spare2;
784                 unsigned char flags;
785         } infos[8];
786         unsigned char spare1[246]; /* Boot information etc. */
787         unsigned short rspeed;     /* Disk rotational speed */
788         unsigned short pcylcount;  /* Physical cylinder count */
789         unsigned short sparecyl;   /* extra sects per cylinder */
790         unsigned char spare2[4];   /* More magic... */
791         unsigned short ilfact;     /* Interleave factor */
792         unsigned short ncyl;       /* Data cylinder count */
793         unsigned short nacyl;      /* Alt. cylinder count */
794         unsigned short ntrks;      /* Tracks per cylinder */
795         unsigned short nsect;      /* Sectors per track */
796         unsigned char spare3[4];   /* Even more magic... */
797         struct sun_partition {
798                 uint32_t start_cylinder;
799                 uint32_t num_sectors;
800         } partitions[8];
801         unsigned short magic;      /* Magic number */
802         unsigned short csum;       /* Label xor'd checksum */
803 } sun_partition;
804
805
806 #define SUN_LABEL_MAGIC          0xDABE
807 #define SUN_LABEL_MAGIC_SWAPPED  0xBEDA
808 #define sunlabel ((sun_partition *)MBRbuffer)
809 #define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
810                                  : (uint16_t)(x))
811 #define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
812                                  : (uint32_t)(x))
813
814
815 #ifdef CONFIG_FEATURE_OSF_LABEL
816 /*
817    Changes:
818    19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
819
820    20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
821    support for OSF/1 disklabels on Alpha.
822    Also fixed unaligned accesses in alpha_bootblock_checksum()
823 */
824
825 #define FREEBSD_PARTITION       0xa5
826 #define NETBSD_PARTITION        0xa9
827
828 static void xbsd_delete_part(void);
829 static void xbsd_new_part(void);
830 static void xbsd_write_disklabel(void);
831 static int xbsd_create_disklabel(void);
832 static void xbsd_edit_disklabel(void);
833 static void xbsd_write_bootstrap(void);
834 static void xbsd_change_fstype(void);
835 static int xbsd_get_part_index(int max);
836 static int xbsd_check_new_partition(int *i);
837 static void xbsd_list_types(void);
838 static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
839 static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
840 static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
841 static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
842
843 #if defined (__alpha__)
844 static void alpha_bootblock_checksum(char *boot);
845 #endif
846
847 #if !defined (__alpha__)
848 static int xbsd_translate_fstype(int linux_type);
849 static void xbsd_link_part(void);
850 static struct partition *xbsd_part;
851 static int xbsd_part_index;
852 #endif
853
854 #if defined (__alpha__)
855 /* We access this through a uint64_t * when checksumming */
856 static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
857 #else
858 static char disklabelbuffer[BSD_BBSIZE];
859 #endif
860
861 static struct xbsd_disklabel xbsd_dlabel;
862
863 #define bsd_cround(n) \
864         (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
865
866 /*
867  * Test whether the whole disk has BSD disk label magic.
868  *
869  * Note: often reformatting with DOS-type label leaves the BSD magic,
870  * so this does not mean that there is a BSD disk label.
871  */
872 static int
873 check_osf_label(void)
874 {
875         if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
876                 return 0;
877         return 1;
878 }
879
880 static void xbsd_print_disklabel(int);
881
882 static int
883 btrydev(const char * dev)
884 {
885         if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
886                 return -1;
887         printf(_("\nBSD label for device: %s\n"), dev);
888         xbsd_print_disklabel (0);
889         return 0;
890 }
891
892 static void
893 bmenu(void)
894 {
895         puts (_("Command action"));
896         puts (_("\td\tdelete a BSD partition"));
897         puts (_("\te\tedit drive data"));
898         puts (_("\ti\tinstall bootstrap"));
899         puts (_("\tl\tlist known filesystem types"));
900         puts (_("\tm\tprint this menu"));
901         puts (_("\tn\tadd a new BSD partition"));
902         puts (_("\tp\tprint BSD partition table"));
903         puts (_("\tq\tquit without saving changes"));
904         puts (_("\tr\treturn to main menu"));
905         puts (_("\ts\tshow complete disklabel"));
906         puts (_("\tt\tchange a partition's filesystem id"));
907         puts (_("\tu\tchange units (cylinders/sectors)"));
908         puts (_("\tw\twrite disklabel to disk"));
909 #if !defined (__alpha__)
910         puts (_("\tx\tlink BSD partition to non-BSD partition"));
911 #endif
912 }
913
914 #if !defined (__alpha__)
915 static int
916 hidden(int type)
917 {
918         return type ^ 0x10;
919 }
920
921 static int
922 is_bsd_partition_type(int type)
923 {
924         return (type == FREEBSD_PARTITION ||
925                 type == hidden(FREEBSD_PARTITION) ||
926                 type == NETBSD_PARTITION ||
927                 type == hidden(NETBSD_PARTITION));
928 }
929 #endif
930
931 static void
932 bselect(void)
933 {
934 #if !defined (__alpha__)
935         int t, ss;
936         struct partition *p;
937
938         for (t = 0; t < 4; t++) {
939                 p = get_part_table(t);
940                 if (p && is_bsd_partition_type(p->sys_ind)) {
941                         xbsd_part = p;
942                         xbsd_part_index = t;
943                         ss = get_start_sect(xbsd_part);
944                         if (ss == 0) {
945                                 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
946                                         partname(disk_device, t+1, 0));
947                                 return;
948                         }
949                                 printf(_("Reading disklabel of %s at sector %d.\n"),
950                                         partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
951                         if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
952                                 if (xbsd_create_disklabel() == 0)
953                                         return;
954                                 break;
955                 }
956         }
957
958         if (t == 4) {
959                 printf(_("There is no *BSD partition on %s.\n"), disk_device);
960                 return;
961         }
962
963 #elif defined (__alpha__)
964
965         if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
966                 if (xbsd_create_disklabel() == 0)
967                         exit (EXIT_SUCCESS);
968
969 #endif
970
971         while (1) {
972                 putchar('\n');
973                 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
974                 case 'd':
975                         xbsd_delete_part();
976                         break;
977                 case 'e':
978                         xbsd_edit_disklabel();
979                         break;
980                 case 'i':
981                         xbsd_write_bootstrap();
982                         break;
983                 case 'l':
984                         xbsd_list_types();
985                         break;
986                 case 'n':
987                         xbsd_new_part();
988                         break;
989                 case 'p':
990                         xbsd_print_disklabel(0);
991                         break;
992                 case 'q':
993                         close(fd);
994                         exit(EXIT_SUCCESS);
995                 case 'r':
996                         return;
997                 case 's':
998                         xbsd_print_disklabel(1);
999                         break;
1000                 case 't':
1001                         xbsd_change_fstype();
1002                         break;
1003                 case 'u':
1004                         change_units();
1005                         break;
1006                 case 'w':
1007                         xbsd_write_disklabel();
1008                         break;
1009 #if !defined (__alpha__)
1010                 case 'x':
1011                         xbsd_link_part();
1012                         break;
1013 #endif
1014                 default:
1015                         bmenu();
1016                         break;
1017                 }
1018         }
1019 }
1020
1021 static void
1022 xbsd_delete_part(void)
1023 {
1024         int i;
1025
1026         i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1027         xbsd_dlabel.d_partitions[i].p_size   = 0;
1028         xbsd_dlabel.d_partitions[i].p_offset = 0;
1029         xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1030         if (xbsd_dlabel.d_npartitions == i + 1)
1031                 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1032                         xbsd_dlabel.d_npartitions--;
1033 }
1034
1035 static void
1036 xbsd_new_part(void)
1037 {
1038         off_t begin, end;
1039         char mesg[256];
1040         int i;
1041
1042         if (!xbsd_check_new_partition(&i))
1043                 return;
1044
1045 #if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1046         begin = get_start_sect(xbsd_part);
1047         end = begin + get_nr_sects(xbsd_part) - 1;
1048 #else
1049         begin = 0;
1050         end = xbsd_dlabel.d_secperunit - 1;
1051 #endif
1052
1053         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1054         begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1055                 0, mesg);
1056
1057         if (display_in_cyl_units)
1058                 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
1059
1060         snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1061                 str_units(SINGULAR));
1062         end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1063                 bsd_cround (begin), mesg);
1064
1065         if (display_in_cyl_units)
1066                 end = end * xbsd_dlabel.d_secpercyl - 1;
1067
1068         xbsd_dlabel.d_partitions[i].p_size   = end - begin + 1;
1069         xbsd_dlabel.d_partitions[i].p_offset = begin;
1070         xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1071 }
1072
1073 static void
1074 xbsd_print_disklabel(int show_all)
1075 {
1076         struct xbsd_disklabel *lp = &xbsd_dlabel;
1077         struct xbsd_partition *pp;
1078         int i, j;
1079
1080         if (show_all) {
1081 #if defined (__alpha__)
1082                 printf("# %s:\n", disk_device);
1083 #else
1084                 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
1085 #endif
1086                 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1087                         printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1088                 else
1089                         printf(_("type: %d\n"), lp->d_type);
1090                 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1091                 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1092                 printf(_("flags:"));
1093                 if (lp->d_flags & BSD_D_REMOVABLE)
1094                         printf(_(" removable"));
1095                 if (lp->d_flags & BSD_D_ECC)
1096                         printf(_(" ecc"));
1097                 if (lp->d_flags & BSD_D_BADSECT)
1098                         printf(_(" badsect"));
1099                 printf("\n");
1100                 /* On various machines the fields of *lp are short/int/long */
1101                 /* In order to avoid problems, we cast them all to long. */
1102                 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1103                 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1104                 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1105                 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1106                 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1107                 printf(_("rpm: %d\n"), lp->d_rpm);
1108                 printf(_("interleave: %d\n"), lp->d_interleave);
1109                 printf(_("trackskew: %d\n"), lp->d_trackskew);
1110                 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1111                 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1112                         (long) lp->d_headswitch);
1113                 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1114                         (long) lp->d_trkseek);
1115                 printf(_("drivedata: "));
1116                 for (i = NDDATA - 1; i >= 0; i--)
1117                         if (lp->d_drivedata[i])
1118                                 break;
1119                 if (i < 0)
1120                         i = 0;
1121                 for (j = 0; j <= i; j++)
1122                         printf("%ld ", (long) lp->d_drivedata[j]);
1123         }
1124         printf(_("\n%d partitions:\n"), lp->d_npartitions);
1125         printf(_("#       start       end      size     fstype   [fsize bsize   cpg]\n"));
1126         pp = lp->d_partitions;
1127         for (i = 0; i < lp->d_npartitions; i++, pp++) {
1128                 if (pp->p_size) {
1129                         if (display_in_cyl_units && lp->d_secpercyl) {
1130                                 printf("  %c: %8ld%c %8ld%c %8ld%c  ",
1131                                         'a' + i,
1132                                         (long) pp->p_offset / lp->d_secpercyl + 1,
1133                                         (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1134                                         (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1135                                         ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1136                                         (long) pp->p_size / lp->d_secpercyl,
1137                                         (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1138                                 );
1139                         } else {
1140                                 printf("  %c: %8ld  %8ld  %8ld   ",
1141                                         'a' + i,
1142                                         (long) pp->p_offset,
1143                                         (long) pp->p_offset + pp->p_size - 1,
1144                                         (long) pp->p_size
1145                                 );
1146                         }
1147
1148                         if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1149                                 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1150                         else
1151                                 printf("%8x", pp->p_fstype);
1152
1153                         switch (pp->p_fstype) {
1154                         case BSD_FS_UNUSED:
1155                                 printf("    %5ld %5ld %5.5s ",
1156                                         (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1157                                 break;
1158                         case BSD_FS_BSDFFS:
1159                                 printf("    %5ld %5ld %5d ",
1160                                         (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1161                                 break;
1162                         default:
1163                                 printf("%22.22s", "");
1164                                 break;
1165                         }
1166                         printf("\n");
1167                 }
1168         }
1169 }
1170
1171 static void
1172 xbsd_write_disklabel(void)
1173 {
1174 #if defined (__alpha__)
1175         printf(_("Writing disklabel to %s.\n"), disk_device);
1176         xbsd_writelabel(NULL, &xbsd_dlabel);
1177 #else
1178         printf(_("Writing disklabel to %s.\n"),
1179                 partname(disk_device, xbsd_part_index + 1, 0));
1180         xbsd_writelabel(xbsd_part, &xbsd_dlabel);
1181 #endif
1182         reread_partition_table(0);      /* no exit yet */
1183 }
1184
1185 static int
1186 xbsd_create_disklabel(void)
1187 {
1188         char c;
1189
1190 #if defined (__alpha__)
1191         fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
1192 #else
1193         fprintf(stderr, _("%s contains no disklabel.\n"),
1194                 partname(disk_device, xbsd_part_index + 1, 0));
1195 #endif
1196
1197         while (1) {
1198                 c = read_char(_("Do you want to create a disklabel? (y/n) "));
1199                 if (c == 'y' || c == 'Y') {
1200                         if (xbsd_initlabel(
1201 #if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
1202         defined (__s390__) || defined (__s390x__)
1203                                 NULL, &xbsd_dlabel
1204 #else
1205                                 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
1206 #endif
1207                                 ) == 1) {
1208                                 xbsd_print_disklabel (1);
1209                                 return 1;
1210                         } else
1211                                 return 0;
1212                 } else if (c == 'n')
1213                         return 0;
1214         }
1215 }
1216
1217 static int
1218 edit_int(int def, char *mesg)
1219 {
1220         do {
1221                 fputs(mesg, stdout);
1222                 printf(" (%d): ", def);
1223                 if (!read_line())
1224                         return def;
1225         }
1226         while (!isdigit(*line_ptr));    /* FIXME: ?!! */
1227         return atoi(line_ptr);
1228 }
1229
1230 static void
1231 xbsd_edit_disklabel(void)
1232 {
1233         struct xbsd_disklabel *d;
1234
1235         d = &xbsd_dlabel;
1236
1237 #if defined (__alpha__) || defined (__ia64__)
1238         d->d_secsize    = (u_long) edit_int((u_long) d->d_secsize     ,_("bytes/sector"));
1239         d->d_nsectors   = (u_long) edit_int((u_long) d->d_nsectors    ,_("sectors/track"));
1240         d->d_ntracks    = (u_long) edit_int((u_long) d->d_ntracks     ,_("tracks/cylinder"));
1241         d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders  ,_("cylinders"));
1242 #endif
1243
1244   /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1245         while (1) {
1246                 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1247                                 _("sectors/cylinder"));
1248                 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1249                         break;
1250
1251                 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1252         }
1253         d->d_rpm        = (u_short) edit_int((u_short) d->d_rpm       ,_("rpm"));
1254         d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1255         d->d_trackskew  = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1256         d->d_cylskew    = (u_short) edit_int((u_short) d->d_cylskew   ,_("cylinderskew"));
1257         d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch  ,_("headswitch"));
1258         d->d_trkseek    = (u_long) edit_int((u_long) d->d_trkseek     ,_("track-to-track seek"));
1259
1260         d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
1261 }
1262
1263 static int
1264 xbsd_get_bootstrap (char *path, void *ptr, int size)
1265 {
1266         int fdb;
1267
1268         if ((fdb = open (path, O_RDONLY)) < 0) {
1269                 perror(path);
1270                 return 0;
1271         }
1272         if (read(fdb, ptr, size) < 0) {
1273                 perror(path);
1274                 close(fdb);
1275                 return 0;
1276         }
1277         printf(" ... %s\n", path);
1278         close(fdb);
1279         return 1;
1280 }
1281
1282 static void
1283 sync_disks(void)
1284 {
1285         printf(_("\nSyncing disks.\n"));
1286         sync();
1287         sleep(4); /* What? */
1288 }
1289
1290 static void
1291 xbsd_write_bootstrap(void)
1292 {
1293         char *bootdir = BSD_LINUX_BOOTDIR;
1294         char path[MAXPATHLEN];
1295         char *dkbasename;
1296         struct xbsd_disklabel dl;
1297         char *d, *p, *e;
1298         int sector;
1299
1300         if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1301                 dkbasename = "sd";
1302         else
1303                 dkbasename = "wd";
1304
1305         printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1306                 dkbasename, dkbasename, dkbasename);
1307         if (read_line()) {
1308                 line_ptr[strlen(line_ptr)-1] = '\0';
1309                 dkbasename = line_ptr;
1310         }
1311         snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1312         if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1313                 return;
1314
1315 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1316         d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1317         memmove(&dl, d, sizeof(struct xbsd_disklabel));
1318
1319 /* The disklabel will be overwritten by 0's from bootxx anyway */
1320         memset(d, 0, sizeof(struct xbsd_disklabel));
1321
1322         snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1323         if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1324                           (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1325                 return;
1326
1327         e = d + sizeof(struct xbsd_disklabel);
1328         for (p = d; p < e; p++)
1329                 if (*p) {
1330                         fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1331                         exit(EXIT_FAILURE);
1332                 }
1333
1334         memmove(d, &dl, sizeof(struct xbsd_disklabel));
1335
1336 #if defined (__powerpc__) || defined (__hppa__)
1337         sector = 0;
1338 #elif defined (__alpha__)
1339         sector = 0;
1340         alpha_bootblock_checksum(disklabelbuffer);
1341 #else
1342         sector = get_start_sect(xbsd_part);
1343 #endif
1344
1345         if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1346                 fdisk_fatal(unable_to_seek);
1347         if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1348                 fdisk_fatal(unable_to_write);
1349
1350 #if defined (__alpha__)
1351         printf(_("Bootstrap installed on %s.\n"), disk_device);
1352 #else
1353         printf(_("Bootstrap installed on %s.\n"),
1354                 partname (disk_device, xbsd_part_index+1, 0));
1355 #endif
1356
1357         sync_disks();
1358 }
1359
1360 static void
1361 xbsd_change_fstype(void)
1362 {
1363         int i;
1364
1365         i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1366         xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
1367 }
1368
1369 static int
1370 xbsd_get_part_index(int max)
1371 {
1372         char prompt[256];
1373         char l;
1374
1375         snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1376         do
1377                         l = tolower(read_char(prompt));
1378         while (l < 'a' || l > 'a' + max - 1);
1379         return l - 'a';
1380 }
1381
1382 static int
1383 xbsd_check_new_partition(int *i)
1384 {
1385         /* room for more? various BSD flavours have different maxima */
1386         if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1387                 int t;
1388
1389                 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1390                         if (xbsd_dlabel.d_partitions[t].p_size == 0)
1391                                 break;
1392
1393                 if (t == BSD_MAXPARTITIONS) {
1394                         fprintf(stderr, _("The maximum number of partitions "
1395                                            "has been created\n"));
1396                         return 0;
1397                 }
1398         }
1399
1400         *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1401
1402         if (*i >= xbsd_dlabel.d_npartitions)
1403                 xbsd_dlabel.d_npartitions = (*i) + 1;
1404
1405         if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1406                 fprintf(stderr, _("This partition already exists.\n"));
1407                 return 0;
1408         }
1409
1410         return 1;
1411 }
1412
1413 static void
1414 xbsd_list_types(void)
1415 {
1416         list_types(xbsd_fstypes);
1417 }
1418
1419 static u_short
1420 xbsd_dkcksum(struct xbsd_disklabel *lp)
1421 {
1422         u_short *start, *end;
1423         u_short sum = 0;
1424
1425         start = (u_short *) lp;
1426         end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1427         while (start < end)
1428                 sum ^= *start++;
1429         return sum;
1430 }
1431
1432 static int
1433 xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1434 {
1435         struct xbsd_partition *pp;
1436
1437         get_geometry();
1438         memset(d, 0, sizeof(struct xbsd_disklabel));
1439
1440         d->d_magic = BSD_DISKMAGIC;
1441
1442         if (strncmp(disk_device, "/dev/sd", 7) == 0)
1443                 d->d_type = BSD_DTYPE_SCSI;
1444         else
1445                 d->d_type = BSD_DTYPE_ST506;
1446
1447 #if !defined (__alpha__)
1448         d->d_flags = BSD_D_DOSPART;
1449 #else
1450         d->d_flags = 0;
1451 #endif
1452         d->d_secsize = SECTOR_SIZE;           /* bytes/sector  */
1453         d->d_nsectors = sectors;            /* sectors/track */
1454         d->d_ntracks = heads;               /* tracks/cylinder (heads) */
1455         d->d_ncylinders = cylinders;
1456         d->d_secpercyl  = sectors * heads;/* sectors/cylinder */
1457         if (d->d_secpercyl == 0)
1458                 d->d_secpercyl = 1;           /* avoid segfaults */
1459         d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
1460
1461         d->d_rpm = 3600;
1462         d->d_interleave = 1;
1463         d->d_trackskew = 0;
1464         d->d_cylskew = 0;
1465         d->d_headswitch = 0;
1466         d->d_trkseek = 0;
1467
1468         d->d_magic2 = BSD_DISKMAGIC;
1469         d->d_bbsize = BSD_BBSIZE;
1470         d->d_sbsize = BSD_SBSIZE;
1471
1472 #if !defined (__alpha__)
1473         d->d_npartitions = 4;
1474         pp = &d->d_partitions[2];             /* Partition C should be
1475                                                    the NetBSD partition */
1476         pp->p_offset = get_start_sect(p);
1477         pp->p_size   = get_nr_sects(p);
1478         pp->p_fstype = BSD_FS_UNUSED;
1479         pp = &d->d_partitions[3];             /* Partition D should be
1480                                                    the whole disk */
1481         pp->p_offset = 0;
1482         pp->p_size   = d->d_secperunit;
1483         pp->p_fstype = BSD_FS_UNUSED;
1484 #elif defined (__alpha__)
1485         d->d_npartitions = 3;
1486         pp = &d->d_partitions[2];             /* Partition C should be
1487                                                    the whole disk */
1488         pp->p_offset = 0;
1489         pp->p_size   = d->d_secperunit;
1490         pp->p_fstype = BSD_FS_UNUSED;
1491 #endif
1492
1493         return 1;
1494 }
1495
1496 /*
1497  * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1498  * If it has the right magic, return 1.
1499  */
1500 static int
1501 xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1502 {
1503         int t, sector;
1504
1505         /* p is used only to get the starting sector */
1506 #if !defined (__alpha__)
1507         sector = (p ? get_start_sect(p) : 0);
1508 #elif defined (__alpha__)
1509         sector = 0;
1510 #endif
1511
1512         if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1513                 fdisk_fatal(unable_to_seek);
1514         if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1515                 fdisk_fatal(unable_to_read);
1516
1517         memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1518                    sizeof(struct xbsd_disklabel));
1519
1520         if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
1521                 return 0;
1522
1523         for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1524                 d->d_partitions[t].p_size   = 0;
1525                 d->d_partitions[t].p_offset = 0;
1526                 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
1527         }
1528
1529         if (d->d_npartitions > BSD_MAXPARTITIONS)
1530                 fprintf(stderr, _("Warning: too many partitions "
1531                                 "(%d, maximum is %d).\n"),
1532                         d->d_npartitions, BSD_MAXPARTITIONS);
1533         return 1;
1534 }
1535
1536 static int
1537 xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1538 {
1539         unsigned int sector;
1540
1541 #if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1542         sector = get_start_sect(p) + BSD_LABELSECTOR;
1543 #else
1544         sector = BSD_LABELSECTOR;
1545 #endif
1546
1547         d->d_checksum = 0;
1548         d->d_checksum = xbsd_dkcksum (d);
1549
1550         /* This is necessary if we want to write the bootstrap later,
1551            otherwise we'd write the old disklabel with the bootstrap.
1552         */
1553         memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1554                 d, sizeof(struct xbsd_disklabel));
1555
1556 #if defined (__alpha__) && BSD_LABELSECTOR == 0
1557         alpha_bootblock_checksum (disklabelbuffer);
1558         if (lseek(fd, 0, SEEK_SET) == -1)
1559                 fdisk_fatal(unable_to_seek);
1560         if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1561                 fdisk_fatal(unable_to_write);
1562 #else
1563         if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1564                 fdisk_fatal(unable_to_seek);
1565         if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1566                 fdisk_fatal(unable_to_write);
1567 #endif
1568         sync_disks();
1569         return 1;
1570 }
1571
1572
1573 #if !defined (__alpha__)
1574 static int
1575 xbsd_translate_fstype(int linux_type)
1576 {
1577         switch (linux_type) {
1578         case 0x01: /* DOS 12-bit FAT   */
1579         case 0x04: /* DOS 16-bit <32M  */
1580         case 0x06: /* DOS 16-bit >=32M */
1581         case 0xe1: /* DOS access       */
1582         case 0xe3: /* DOS R/O          */
1583         case 0xf2: /* DOS secondary    */
1584                 return BSD_FS_MSDOS;
1585         case 0x07: /* OS/2 HPFS        */
1586                 return BSD_FS_HPFS;
1587         default:
1588                 return BSD_FS_OTHER;
1589         }
1590 }
1591
1592 static void
1593 xbsd_link_part(void)
1594 {
1595         int k, i;
1596         struct partition *p;
1597
1598         k = get_partition(1, partitions);
1599
1600         if (!xbsd_check_new_partition(&i))
1601                 return;
1602
1603         p = get_part_table(k);
1604
1605         xbsd_dlabel.d_partitions[i].p_size   = get_nr_sects(p);
1606         xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1607         xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1608 }
1609 #endif
1610
1611 #if defined (__alpha__)
1612
1613 #if !defined(__GLIBC__)
1614 typedef unsigned long long uint64_t;
1615 #endif
1616
1617 static void
1618 alpha_bootblock_checksum(char *boot)
1619 {
1620         uint64_t *dp, sum;
1621         int i;
1622
1623         dp = (uint64_t *)boot;
1624         sum = 0;
1625         for (i = 0; i < 63; i++)
1626                 sum += dp[i];
1627         dp[63] = sum;
1628 }
1629 #endif /* __alpha__ */
1630
1631 #endif /* OSF_LABEL */
1632
1633 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1634 static unsigned short
1635 __swap16(unsigned short x)
1636 {
1637         return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
1638 }
1639
1640 static uint32_t
1641 __swap32(uint32_t x)
1642 {
1643         return (((x & 0xFF) << 24) |
1644                 ((x & 0xFF00) << 8) |
1645                 ((x & 0xFF0000) >> 8) |
1646                 ((x & 0xFF000000) >> 24));
1647 }
1648 #endif
1649
1650 #ifdef CONFIG_FEATURE_SGI_LABEL
1651 /*
1652  *
1653  * fdisksgilabel.c
1654  *
1655  * Copyright (C) Andreas Neuper, Sep 1998.
1656  *      This file may be modified and redistributed under
1657  *      the terms of the GNU Public License.
1658  *
1659  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1660  *      Internationalization
1661  */
1662
1663
1664 static int sgi_other_endian;
1665 static int debug;
1666 static short sgi_volumes = 1;
1667
1668 /*
1669  * only dealing with free blocks here
1670  */
1671
1672 typedef struct {
1673         unsigned int first;
1674         unsigned int last;
1675 } freeblocks;
1676 static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1677
1678 static void
1679 setfreelist(int i, unsigned int f, unsigned int l)
1680 {
1681         freelist[i].first = f;
1682         freelist[i].last = l;
1683 }
1684
1685 static void
1686 add2freelist(unsigned int f, unsigned int l)
1687 {
1688         int i;
1689         for (i = 0; i < 17 ; i++)
1690                 if (freelist[i].last == 0)
1691                         break;
1692         setfreelist(i, f, l);
1693 }
1694
1695 static void
1696 clearfreelist(void)
1697 {
1698         int i;
1699
1700         for (i = 0; i < 17 ; i++)
1701                 setfreelist(i, 0, 0);
1702 }
1703
1704 static unsigned int
1705 isinfreelist(unsigned int b)
1706 {
1707         int i;
1708
1709         for (i = 0; i < 17 ; i++)
1710                 if (freelist[i].first <= b && freelist[i].last >= b)
1711                         return freelist[i].last;
1712         return 0;
1713 }
1714         /* return last vacant block of this stride (never 0). */
1715         /* the '>=' is not quite correct, but simplifies the code */
1716 /*
1717  * end of free blocks section
1718  */
1719
1720 static const struct systypes sgi_sys_types[] = {
1721 /* SGI_VOLHDR   */      { "\x00" "SGI volhdr"   },
1722 /* 0x01         */      { "\x01" "SGI trkrepl"  },
1723 /* 0x02         */      { "\x02" "SGI secrepl"  },
1724 /* SGI_SWAP     */      { "\x03" "SGI raw"      },
1725 /* 0x04         */      { "\x04" "SGI bsd"      },
1726 /* 0x05         */      { "\x05" "SGI sysv"     },
1727 /* ENTIRE_DISK  */      { "\x06" "SGI volume"   },
1728 /* SGI_EFS      */      { "\x07" "SGI efs"      },
1729 /* 0x08         */      { "\x08" "SGI lvol"     },
1730 /* 0x09         */      { "\x09" "SGI rlvol"    },
1731 /* SGI_XFS      */      { "\x0a" "SGI xfs"      },
1732 /* SGI_XFSLOG   */      { "\x0b" "SGI xfslog"   },
1733 /* SGI_XLV      */      { "\x0c" "SGI xlv"      },
1734 /* SGI_XVM      */      { "\x0d" "SGI xvm"      },
1735 /* LINUX_SWAP   */      { "\x82" "Linux swap"   },
1736 /* LINUX_NATIVE */      { "\x83" "Linux native" },
1737 /* LINUX_LVM    */      { "\x8d" "Linux LVM"    },
1738 /* LINUX_RAID   */      { "\xfd" "Linux RAID"   },
1739                         { NULL             }
1740 };
1741
1742
1743 static int
1744 sgi_get_nsect(void)
1745 {
1746         return SGI_SSWAP16(sgilabel->devparam.nsect);
1747 }
1748
1749 static int
1750 sgi_get_ntrks(void)
1751 {
1752         return SGI_SSWAP16(sgilabel->devparam.ntrks);
1753 }
1754
1755 static unsigned int
1756 two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1757 {
1758         int i = 0;
1759         unsigned int sum = 0;
1760
1761         size /= sizeof(unsigned int);
1762         for (i = 0; i < size; i++)
1763                 sum -= SGI_SSWAP32(base[i]);
1764         return sum;
1765 }
1766
1767 static int
1768 check_sgi_label(void)
1769 {
1770         if (sizeof(sgilabel) > 512) {
1771                 fprintf(stderr,
1772                         _("According to MIPS Computer Systems, Inc the "
1773                         "Label must not contain more than 512 bytes\n"));
1774                 exit(1);
1775         }
1776
1777         if (sgilabel->magic != SGI_LABEL_MAGIC
1778          && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1779                 current_label_type = label_dos;
1780                 return 0;
1781         }
1782
1783         sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1784         /*
1785          * test for correct checksum
1786          */
1787         if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1788                                 sizeof(*sgilabel))) {
1789                 fprintf(stderr,
1790                         _("Detected sgi disklabel with wrong checksum.\n"));
1791         }
1792         update_units();
1793         current_label_type = label_sgi;
1794         partitions = 16;
1795         sgi_volumes = 15;
1796         return 1;
1797 }
1798
1799 static unsigned int
1800 sgi_get_start_sector(int i)
1801 {
1802         return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1803 }
1804
1805 static unsigned int
1806 sgi_get_num_sectors(int i)
1807 {
1808         return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1809 }
1810
1811 static int
1812 sgi_get_sysid(int i)
1813 {
1814         return SGI_SSWAP32(sgilabel->partitions[i].id);
1815 }
1816
1817 static int
1818 sgi_get_bootpartition(void)
1819 {
1820         return SGI_SSWAP16(sgilabel->boot_part);
1821 }
1822
1823 static int
1824 sgi_get_swappartition(void)
1825 {
1826         return SGI_SSWAP16(sgilabel->swap_part);
1827 }
1828
1829 static void
1830 sgi_list_table(int xtra)
1831 {
1832         int i, w, wd;
1833         int kpi = 0;                /* kernel partition ID */
1834
1835         if(xtra) {
1836                 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1837                         "%d cylinders, %d physical cylinders\n"
1838                         "%d extra sects/cyl, interleave %d:1\n"
1839                         "%s\n"
1840                         "Units = %s of %d * 512 bytes\n\n"),
1841                         disk_device, heads, sectors, cylinders,
1842                         SGI_SSWAP16(sgiparam.pcylcount),
1843                         SGI_SSWAP16(sgiparam.sparecyl),
1844                         SGI_SSWAP16(sgiparam.ilfact),
1845                         (char *)sgilabel,
1846                         str_units(PLURAL), units_per_sector);
1847         } else {
1848                 printf( _("\nDisk %s (SGI disk label): "
1849                         "%d heads, %d sectors, %d cylinders\n"
1850                         "Units = %s of %d * 512 bytes\n\n"),
1851                         disk_device, heads, sectors, cylinders,
1852                         str_units(PLURAL), units_per_sector );
1853         }
1854
1855         w = strlen(disk_device);
1856         wd = strlen(_("Device"));
1857         if (w < wd)
1858         w = wd;
1859
1860         printf(_("----- partitions -----\n"
1861                 "Pt# %*s  Info     Start       End   Sectors  Id  System\n"),
1862                 w + 2, _("Device"));
1863         for (i = 0 ; i < partitions; i++) {
1864                 if( sgi_get_num_sectors(i) || debug ) {
1865                         uint32_t start = sgi_get_start_sector(i);
1866                         uint32_t len = sgi_get_num_sectors(i);
1867                         kpi++;              /* only count nonempty partitions */
1868                         printf(
1869                         "%2d: %s %4s %9ld %9ld %9ld  %2x  %s\n",
1870 /* fdisk part number */ i+1,
1871 /* device */            partname(disk_device, kpi, w+3),
1872 /* flags */             (sgi_get_swappartition() == i) ? "swap" :
1873 /* flags */             (sgi_get_bootpartition() == i) ? "boot" : "    ",
1874 /* start */             (long) scround(start),
1875 /* end */               (long) scround(start+len)-1,
1876 /* no odd flag on end */(long) len,
1877 /* type id */           sgi_get_sysid(i),
1878 /* type name */         partition_type(sgi_get_sysid(i)));
1879                 }
1880         }
1881         printf(_("----- Bootinfo -----\nBootfile: %s\n"
1882                 "----- Directory Entries -----\n"),
1883                 sgilabel->boot_file);
1884         for (i = 0 ; i < sgi_volumes; i++) {
1885                 if (sgilabel->directory[i].vol_file_size) {
1886                         uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1887                         uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1888                         unsigned char *name = sgilabel->directory[i].vol_file_name;
1889
1890                         printf(_("%2d: %-10s sector%5u size%8u\n"),
1891                                 i, (char*)name, (unsigned int) start, (unsigned int) len);
1892                 }
1893         }
1894 }
1895
1896 static void
1897 sgi_set_bootpartition(int i)
1898 {
1899         sgilabel->boot_part = SGI_SSWAP16(((short)i));
1900 }
1901
1902 static unsigned int
1903 sgi_get_lastblock(void)
1904 {
1905         return heads * sectors * cylinders;
1906 }
1907
1908 static void
1909 sgi_set_swappartition(int i)
1910 {
1911         sgilabel->swap_part = SGI_SSWAP16(((short)i));
1912 }
1913
1914 static int
1915 sgi_check_bootfile(const char* aFile)
1916 {
1917         if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1918                 printf(_("\nInvalid Bootfile!\n"
1919                         "\tThe bootfile must be an absolute non-zero pathname,\n"
1920                         "\te.g. \"/unix\" or \"/unix.save\".\n"));
1921                 return 0;
1922         } else {
1923                 if (strlen(aFile) > 16) {
1924                         printf(_("\n\tName of Bootfile too long:  "
1925                                 "16 bytes maximum.\n"));
1926                         return 0;
1927                 } else {
1928                         if (aFile[0] != '/') {
1929                                 printf(_("\n\tBootfile must have a "
1930                                         "fully qualified pathname.\n"));
1931                                 return 0;
1932                         }
1933                 }
1934         }
1935         if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
1936                 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1937                          "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
1938                 /* filename is correct and did change */
1939                 return 1;
1940         }
1941         return 0;   /* filename did not change */
1942 }
1943
1944 static const char *
1945 sgi_get_bootfile(void)
1946 {
1947         return (char*)sgilabel->boot_file;
1948 }
1949
1950 static void
1951 sgi_set_bootfile(const char* aFile)
1952 {
1953         int i = 0;
1954
1955         if (sgi_check_bootfile(aFile)) {
1956                 while (i < 16) {
1957                         if ((aFile[i] != '\n')  /* in principle caught again by next line */
1958                          && (strlen(aFile) > i))
1959                                 sgilabel->boot_file[i] = aFile[i];
1960                         else
1961                                 sgilabel->boot_file[i] = 0;
1962                         i++;
1963                 }
1964                 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
1965         }
1966 }
1967
1968 static void
1969 create_sgiinfo(void)
1970 {
1971         /* I keep SGI's habit to write the sgilabel to the second block */
1972         sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1973         sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1974         strcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel");
1975 }
1976
1977 static sgiinfo *fill_sgiinfo(void);
1978
1979 static void
1980 sgi_write_table(void)
1981 {
1982         sgilabel->csum = 0;
1983         sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1984                         (unsigned int*)sgilabel, sizeof(*sgilabel)));
1985         assert(two_s_complement_32bit_sum(
1986                 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
1987
1988         if (lseek(fd, 0, SEEK_SET) < 0)
1989                 fdisk_fatal(unable_to_seek);
1990         if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1991                 fdisk_fatal(unable_to_write);
1992         if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
1993                 /*
1994                  * keep this habit of first writing the "sgilabel".
1995                  * I never tested whether it works without (AN 981002).
1996                  */
1997                 sgiinfo *info = fill_sgiinfo();
1998                 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
1999                 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2000                         fdisk_fatal(unable_to_seek);
2001                 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2002                         fdisk_fatal(unable_to_write);
2003                 free(info);
2004         }
2005 }
2006
2007 static int
2008 compare_start(int *x, int *y)
2009 {
2010         /*
2011          * sort according to start sectors
2012          * and prefers largest partition:
2013          * entry zero is entire disk entry
2014          */
2015         unsigned int i = *x;
2016         unsigned int j = *y;
2017         unsigned int a = sgi_get_start_sector(i);
2018         unsigned int b = sgi_get_start_sector(j);
2019         unsigned int c = sgi_get_num_sectors(i);
2020         unsigned int d = sgi_get_num_sectors(j);
2021
2022         if (a == b)
2023                 return (d > c) ? 1 : (d == c) ? 0 : -1;
2024         return (a > b) ? 1 : -1;
2025 }
2026
2027
2028 static int
2029 verify_sgi(int verbose)
2030 {
2031         int Index[16];      /* list of valid partitions */
2032         int sortcount = 0;  /* number of used partitions, i.e. non-zero lengths */
2033         int entire = 0, i = 0;
2034         unsigned int start = 0;
2035         long long gap = 0;      /* count unused blocks */
2036         unsigned int lastblock = sgi_get_lastblock();
2037
2038         clearfreelist();
2039         for (i = 0; i < 16; i++) {
2040                 if (sgi_get_num_sectors(i) != 0) {
2041                         Index[sortcount++] = i;
2042                         if (sgi_get_sysid(i) == ENTIRE_DISK) {
2043                                 if (entire++ == 1) {
2044                                         if (verbose)
2045                                                 printf(_("More than one entire disk entry present.\n"));
2046                                 }
2047                         }
2048                 }
2049         }
2050         if (sortcount == 0) {
2051                 if (verbose)
2052                         printf(_("No partitions defined\n"));
2053                 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2054         }
2055         qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2056         if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2057                 if ((Index[0] != 10) && verbose)
2058                         printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2059                 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2060                         printf(_("The entire disk partition should start "
2061                                 "at block 0,\n"
2062                                 "not at diskblock %d.\n"),
2063                 sgi_get_start_sector(Index[0]));
2064                 if (debug)      /* I do not understand how some disks fulfil it */
2065                         if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2066                                 printf(_("The entire disk partition is only %d diskblock large,\n"
2067                                         "but the disk is %d diskblocks long.\n"),
2068                 sgi_get_num_sectors(Index[0]), lastblock);
2069                 lastblock = sgi_get_num_sectors(Index[0]);
2070         } else {
2071                 if (verbose)
2072                         printf(_("One Partition (#11) should cover the entire disk.\n"));
2073                 if (debug > 2)
2074                         printf("sysid=%d\tpartition=%d\n",
2075                                 sgi_get_sysid(Index[0]), Index[0]+1);
2076         }
2077         for (i = 1, start = 0; i < sortcount; i++) {
2078                 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2079
2080                 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2081                         if (debug)      /* I do not understand how some disks fulfil it */
2082                                 if (verbose)
2083                                         printf(_("Partition %d does not start on cylinder boundary.\n"),
2084                                                 Index[i]+1);
2085                 }
2086                 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2087                         if (debug)      /* I do not understand how some disks fulfil it */
2088                                 if (verbose)
2089                                         printf(_("Partition %d does not end on cylinder boundary.\n"),
2090                                                 Index[i]+1);
2091                 }
2092                 /* We cannot handle several "entire disk" entries. */
2093                 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2094                 if (start > sgi_get_start_sector(Index[i])) {
2095                         if (verbose)
2096                                 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2097                                         Index[i-1]+1, Index[i]+1,
2098                                         start - sgi_get_start_sector(Index[i]));
2099                         if (gap >  0) gap = -gap;
2100                         if (gap == 0) gap = -1;
2101                 }
2102                 if (start < sgi_get_start_sector(Index[i])) {
2103                         if (verbose)
2104                                 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2105                                         sgi_get_start_sector(Index[i]) - start,
2106                                         start, sgi_get_start_sector(Index[i])-1);
2107                         gap += sgi_get_start_sector(Index[i]) - start;
2108                         add2freelist(start, sgi_get_start_sector(Index[i]));
2109                 }
2110                 start = sgi_get_start_sector(Index[i])
2111                            + sgi_get_num_sectors(Index[i]);
2112                 if (debug > 1) {
2113                         if (verbose)
2114                                 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2115                                         sgi_get_start_sector(Index[i]),
2116                                         sgi_get_num_sectors(Index[i]),
2117                                         sgi_get_sysid(Index[i]));
2118                 }
2119         }
2120         if (start < lastblock) {
2121                 if (verbose)
2122                         printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2123                                 lastblock - start, start, lastblock-1);
2124                 gap += lastblock - start;
2125                 add2freelist(start, lastblock);
2126         }
2127         /*
2128          * Done with arithmetics
2129          * Go for details now
2130          */
2131         if (verbose) {
2132                 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2133                         printf(_("\nThe boot partition does not exist.\n"));
2134                 }
2135                 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2136                         printf(_("\nThe swap partition does not exist.\n"));
2137                 } else {
2138                         if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2139                          && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2140                                 printf(_("\nThe swap partition has no swap type.\n"));
2141                 }
2142                 if (sgi_check_bootfile("/unix"))
2143                         printf(_("\tYou have chosen an unusual boot file name.\n"));
2144         }
2145         return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
2146 }
2147
2148 static int
2149 sgi_gaps(void)
2150 {
2151         /*
2152          * returned value is:
2153          *  = 0 : disk is properly filled to the rim
2154          *  < 0 : there is an overlap
2155          *  > 0 : there is still some vacant space
2156          */
2157         return verify_sgi(0);
2158 }
2159
2160 static void
2161 sgi_change_sysid(int i, int sys)
2162 {
2163         if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2164                 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2165                 return;
2166         }
2167         if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2168          && (sgi_get_start_sector(i) < 1) ) {
2169                 read_chars(
2170                         _("It is highly recommended that the partition at offset 0\n"
2171                         "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2172                         "retrieve from its directory standalone tools like sash and fx.\n"
2173                         "Only the \"SGI volume\" entire disk section may violate this.\n"
2174                         "Type YES if you are sure about tagging this partition differently.\n"));
2175                 if (strcmp(line_ptr, _("YES\n")))
2176                         return;
2177         }
2178         sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2179 }
2180
2181 /* returns partition index of first entry marked as entire disk */
2182 static int
2183 sgi_entire(void)
2184 {
2185         int i;
2186
2187         for (i = 0; i < 16; i++)
2188                 if (sgi_get_sysid(i) == SGI_VOLUME)
2189                         return i;
2190         return -1;
2191 }
2192
2193 static void
2194 sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2195 {
2196         sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2197         sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2198         sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2199         set_changed(i);
2200         if (sgi_gaps() < 0)     /* rebuild freelist */
2201                 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2202 }
2203
2204 static void
2205 sgi_set_entire(void)
2206 {
2207         int n;
2208
2209         for (n = 10; n < partitions; n++) {
2210                 if(!sgi_get_num_sectors(n) ) {
2211                         sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2212                         break;
2213                 }
2214         }
2215 }
2216
2217 static void
2218 sgi_set_volhdr(void)
2219 {
2220         int n;
2221
2222         for (n = 8; n < partitions; n++) {
2223         if (!sgi_get_num_sectors(n)) {
2224                 /*
2225                  * 5 cylinders is an arbitrary value I like
2226                  * IRIX 5.3 stored files in the volume header
2227                  * (like sash, symmon, fx, ide) with ca. 3200
2228                  * sectors.
2229                  */
2230                 if (heads * sectors * 5 < sgi_get_lastblock())
2231                         sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2232                         break;
2233                 }
2234         }
2235 }
2236
2237 static void
2238 sgi_delete_partition(int i)
2239 {
2240         sgi_set_partition(i, 0, 0, 0);
2241 }
2242
2243 static void
2244 sgi_add_partition(int n, int sys)
2245 {
2246         char mesg[256];
2247         unsigned int first = 0, last = 0;
2248
2249         if (n == 10) {
2250                 sys = SGI_VOLUME;
2251         } else if (n == 8) {
2252                 sys = 0;
2253         }
2254         if(sgi_get_num_sectors(n)) {
2255                 printf(_("Partition %d is already defined.  Delete "
2256                         "it before re-adding it.\n"), n + 1);
2257                 return;
2258         }
2259         if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2260                 printf(_("Attempting to generate entire disk entry automatically.\n"));
2261                 sgi_set_entire();
2262                 sgi_set_volhdr();
2263         }
2264         if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2265                 printf(_("The entire disk is already covered with partitions.\n"));
2266                 return;
2267         }
2268         if (sgi_gaps() < 0) {
2269                 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2270                 return;
2271         }
2272         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2273         while (1) {
2274                 if(sys == SGI_VOLUME) {
2275                         last = sgi_get_lastblock();
2276                         first = read_int(0, 0, last-1, 0, mesg);
2277                         if (first != 0) {
2278                                 printf(_("It is highly recommended that eleventh partition\n"
2279                                                 "covers the entire disk and is of type `SGI volume'\n"));
2280                         }
2281                 } else {
2282                         first = freelist[0].first;
2283                         last  = freelist[0].last;
2284                         first = read_int(scround(first), scround(first), scround(last)-1,
2285                                 0, mesg);
2286                 }
2287                 if (display_in_cyl_units)
2288                         first *= units_per_sector;
2289                 else
2290                         first = first; /* align to cylinder if you know how ... */
2291                 if(!last )
2292                         last = isinfreelist(first);
2293                 if(last == 0) {
2294                         printf(_("You will get a partition overlap on the disk. "
2295                                 "Fix it first!\n"));
2296                 } else
2297                         break;
2298         }
2299         snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2300         last = read_int(scround(first), scround(last)-1, scround(last)-1,
2301                         scround(first), mesg)+1;
2302         if (display_in_cyl_units)
2303                 last *= units_per_sector;
2304         else
2305                 last = last; /* align to cylinder if You know how ... */
2306         if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2307                 printf(_("It is highly recommended that eleventh partition\n"
2308                         "covers the entire disk and is of type `SGI volume'\n"));
2309         sgi_set_partition(n, first, last-first, sys);
2310 }
2311
2312 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
2313 static void
2314 create_sgilabel(void)
2315 {
2316         struct hd_geometry geometry;
2317         struct {
2318                 unsigned int start;
2319                 unsigned int nsect;
2320                 int sysid;
2321         } old[4];
2322         int i = 0;
2323         long longsectors;               /* the number of sectors on the device */
2324         int res;                        /* the result from the ioctl */
2325         int sec_fac;                    /* the sector factor */
2326
2327         sec_fac = sector_size / 512;    /* determine the sector factor */
2328
2329         fprintf( stderr,
2330                 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2331                 "until you decide to write them. After that, of course, the previous\n"
2332                 "content will be unrecoverably lost.\n\n"));
2333
2334         sgi_other_endian = (BB_LITTLE_ENDIAN);
2335         res = ioctl(fd, BLKGETSIZE, &longsectors);
2336         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2337                 heads = geometry.heads;
2338                 sectors = geometry.sectors;
2339                 if (res == 0) {
2340                         /* the get device size ioctl was successful */
2341                         cylinders = longsectors / (heads * sectors);
2342                         cylinders /= sec_fac;
2343                 } else {
2344                         /* otherwise print error and use truncated version */
2345                         cylinders = geometry.cylinders;
2346                         fprintf(stderr,
2347                                 _("Warning:  BLKGETSIZE ioctl failed on %s.  "
2348                                 "Using geometry cylinder value of %d.\n"
2349                                 "This value may be truncated for devices"
2350                                 " > 33.8 GB.\n"), disk_device, cylinders);
2351                 }
2352         }
2353         for (i = 0; i < 4; i++) {
2354                 old[i].sysid = 0;
2355                 if (valid_part_table_flag(MBRbuffer)) {
2356                         if(get_part_table(i)->sys_ind) {
2357                                 old[i].sysid = get_part_table(i)->sys_ind;
2358                                 old[i].start = get_start_sect(get_part_table(i));
2359                                 old[i].nsect = get_nr_sects(get_part_table(i));
2360                                 printf(_("Trying to keep parameters of partition %d.\n"), i);
2361                                 if (debug)
2362                                         printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2363                                 old[i].sysid, old[i].start, old[i].nsect);
2364                         }
2365                 }
2366         }
2367
2368         memset(MBRbuffer, 0, sizeof(MBRbuffer));
2369         sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2370         sgilabel->boot_part = SGI_SSWAP16(0);
2371         sgilabel->swap_part = SGI_SSWAP16(1);
2372
2373         /* sizeof(sgilabel->boot_file) = 16 > 6 */
2374         memset(sgilabel->boot_file, 0, 16);
2375         strcpy((char*)sgilabel->boot_file, "/unix");
2376
2377         sgilabel->devparam.skew                     = (0);
2378         sgilabel->devparam.gap1                     = (0);
2379         sgilabel->devparam.gap2                     = (0);
2380         sgilabel->devparam.sparecyl                 = (0);
2381         sgilabel->devparam.pcylcount                = SGI_SSWAP16(geometry.cylinders);
2382         sgilabel->devparam.head_vol0                = SGI_SSWAP16(0);
2383         sgilabel->devparam.ntrks                    = SGI_SSWAP16(geometry.heads);
2384                                                 /* tracks/cylinder (heads) */
2385         sgilabel->devparam.cmd_tag_queue_depth      = (0);
2386         sgilabel->devparam.unused0                  = (0);
2387         sgilabel->devparam.unused1                  = SGI_SSWAP16(0);
2388         sgilabel->devparam.nsect                    = SGI_SSWAP16(geometry.sectors);
2389                                                 /* sectors/track */
2390         sgilabel->devparam.bytes                    = SGI_SSWAP16(512);
2391         sgilabel->devparam.ilfact                   = SGI_SSWAP16(1);
2392         sgilabel->devparam.flags                    = SGI_SSWAP32(TRACK_FWD|
2393                                                         IGNORE_ERRORS|RESEEK);
2394         sgilabel->devparam.datarate                 = SGI_SSWAP32(0);
2395         sgilabel->devparam.retries_on_error         = SGI_SSWAP32(1);
2396         sgilabel->devparam.ms_per_word              = SGI_SSWAP32(0);
2397         sgilabel->devparam.xylogics_gap1            = SGI_SSWAP16(0);
2398         sgilabel->devparam.xylogics_syncdelay       = SGI_SSWAP16(0);
2399         sgilabel->devparam.xylogics_readdelay       = SGI_SSWAP16(0);
2400         sgilabel->devparam.xylogics_gap2            = SGI_SSWAP16(0);
2401         sgilabel->devparam.xylogics_readgate        = SGI_SSWAP16(0);
2402         sgilabel->devparam.xylogics_writecont       = SGI_SSWAP16(0);
2403         memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2404         memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2405         current_label_type = label_sgi;
2406         partitions = 16;
2407         sgi_volumes = 15;
2408         sgi_set_entire();
2409         sgi_set_volhdr();
2410         for (i = 0; i < 4; i++) {
2411                 if(old[i].sysid) {
2412                         sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2413                 }
2414         }
2415 }
2416
2417 static void
2418 sgi_set_xcyl(void)
2419 {
2420         /* do nothing in the beginning */
2421 }
2422 #endif /* CONFIG_FEATURE_FDISK_ADVANCED */
2423
2424 /* _____________________________________________________________
2425  */
2426
2427 static sgiinfo *
2428 fill_sgiinfo(void)
2429 {
2430         sgiinfo *info = calloc(1, sizeof(sgiinfo));
2431
2432         info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2433         info->b1 = SGI_SSWAP32(-1);
2434         info->b2 = SGI_SSWAP16(-1);
2435         info->b3 = SGI_SSWAP16(1);
2436         /* You may want to replace this string !!!!!!! */
2437         strcpy( (char*)info->scsi_string, "IBM OEM 0662S12         3 30" );
2438         strcpy( (char*)info->serial, "0000" );
2439         info->check1816 = SGI_SSWAP16(18*256 +16 );
2440         strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2441         return info;
2442 }
2443 #endif /* SGI_LABEL */
2444
2445
2446 #ifdef CONFIG_FEATURE_SUN_LABEL
2447 /*
2448  * fdisksunlabel.c
2449  *
2450  * I think this is mostly, or entirely, due to
2451  *      Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2452  *
2453  * Merged with fdisk for other architectures, aeb, June 1998.
2454  *
2455  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2456  *      Internationalization
2457  */
2458
2459
2460 static int sun_other_endian;
2461 static int scsi_disk;
2462 static int floppy;
2463
2464 #ifndef IDE0_MAJOR
2465 #define IDE0_MAJOR 3
2466 #endif
2467 #ifndef IDE1_MAJOR
2468 #define IDE1_MAJOR 22
2469 #endif
2470
2471 static void
2472 guess_device_type(void)
2473 {
2474         struct stat bootstat;
2475
2476         if (fstat(fd, &bootstat) < 0) {
2477                 scsi_disk = 0;
2478                 floppy = 0;
2479         } else if (S_ISBLK(bootstat.st_mode)
2480                 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2481                     major(bootstat.st_rdev) == IDE1_MAJOR)) {
2482                 scsi_disk = 0;
2483                 floppy = 0;
2484         } else if (S_ISBLK(bootstat.st_mode)
2485                 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
2486                 scsi_disk = 0;
2487                 floppy = 1;
2488         } else {
2489                 scsi_disk = 1;
2490                 floppy = 0;
2491         }
2492 }
2493
2494 static const struct systypes sun_sys_types[] = {
2495         { "\x00" "Empty"        }, /* 0            */
2496         { "\x01" "Boot"         }, /* 1            */
2497         { "\x02" "SunOS root"   }, /* 2            */
2498         { "\x03" "SunOS swap"   }, /* SUNOS_SWAP   */
2499         { "\x04" "SunOS usr"    }, /* 4            */
2500         { "\x05" "Whole disk"   }, /* WHOLE_DISK   */
2501         { "\x06" "SunOS stand"  }, /* 6            */
2502         { "\x07" "SunOS var"    }, /* 7            */
2503         { "\x08" "SunOS home"   }, /* 8            */
2504         { "\x82" "Linux swap"   }, /* LINUX_SWAP   */
2505         { "\x83" "Linux native" }, /* LINUX_NATIVE */
2506         { "\x8e" "Linux LVM"    }, /* 0x8e         */
2507 /* New (2.2.x) raid partition with autodetect using persistent superblock */
2508         { "\xfd" "Linux raid autodetect" }, /* 0xfd         */
2509         { NULL }
2510 };
2511
2512
2513 static void
2514 set_sun_partition(int i, uint start, uint stop, int sysid)
2515 {
2516         sunlabel->infos[i].id = sysid;
2517         sunlabel->partitions[i].start_cylinder =
2518                 SUN_SSWAP32(start / (heads * sectors));
2519         sunlabel->partitions[i].num_sectors =
2520                 SUN_SSWAP32(stop - start);
2521         set_changed(i);
2522 }
2523
2524 static int
2525 check_sun_label(void)
2526 {
2527         unsigned short *ush;
2528         int csum;
2529
2530         if (sunlabel->magic != SUN_LABEL_MAGIC
2531          && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2532                 current_label_type = label_dos;
2533                 sun_other_endian = 0;
2534                 return 0;
2535         }
2536         sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2537         ush = ((unsigned short *) (sunlabel + 1)) - 1;
2538         for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2539         if (csum) {
2540                 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2541                                 "Probably you'll have to set all the values,\n"
2542                                 "e.g. heads, sectors, cylinders and partitions\n"
2543                                 "or force a fresh label (s command in main menu)\n"));
2544         } else {
2545                 heads = SUN_SSWAP16(sunlabel->ntrks);
2546                 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2547                 sectors = SUN_SSWAP16(sunlabel->nsect);
2548         }
2549         update_units();
2550         current_label_type = label_sun;
2551         partitions = 8;
2552         return 1;
2553 }
2554
2555 static const struct sun_predefined_drives {
2556         const char *vendor;
2557         const char *model;
2558         unsigned short sparecyl;
2559         unsigned short ncyl;
2560         unsigned short nacyl;
2561         unsigned short pcylcount;
2562         unsigned short ntrks;
2563         unsigned short nsect;
2564         unsigned short rspeed;
2565 } sun_drives[] = {
2566         { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2567         { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2568         { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2569         { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2570         { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2571         { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2572         { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2573         { "","SUN0104",1,974,2,1019,6,35,3662},
2574         { "","SUN0207",4,1254,2,1272,9,36,3600},
2575         { "","SUN0327",3,1545,2,1549,9,46,3600},
2576         { "","SUN0340",0,1538,2,1544,6,72,4200},
2577         { "","SUN0424",2,1151,2,2500,9,80,4400},
2578         { "","SUN0535",0,1866,2,2500,7,80,5400},
2579         { "","SUN0669",5,1614,2,1632,15,54,3600},
2580         { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2581         { "","SUN1.05",0,2036,2,2038,14,72,5400},
2582         { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2583         { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2584         { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2585 };
2586
2587 static const struct sun_predefined_drives *
2588 sun_autoconfigure_scsi(void)
2589 {
2590         const struct sun_predefined_drives *p = NULL;
2591
2592 #ifdef SCSI_IOCTL_GET_IDLUN
2593         unsigned int id[2];
2594         char buffer[2048];
2595         char buffer2[2048];
2596         FILE *pfd;
2597         char *vendor;
2598         char *model;
2599         char *q;
2600         int i;
2601
2602         if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2603                 sprintf(buffer,
2604                         "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2605                         /* This is very wrong (works only if you have one HBA),
2606                            but I haven't found a way how to get hostno
2607                            from the current kernel */
2608                         0,
2609                         (id[0]>>16) & 0xff,
2610                         id[0] & 0xff,
2611                         (id[0]>>8) & 0xff
2612                 );
2613                 pfd = fopen("/proc/scsi/scsi","r");
2614                 if (pfd) {
2615                         while (fgets(buffer2, 2048, pfd)) {
2616                                 if (!strcmp(buffer, buffer2)) {
2617                                         if (fgets(buffer2,2048,pfd)) {
2618                                                 q = strstr(buffer2,"Vendor: ");
2619                                                 if (q) {
2620                                                         q += 8;
2621                                                         vendor = q;
2622                                                         q = strstr(q," ");
2623                                                         *q++ = 0;   /* truncate vendor name */
2624                                                         q = strstr(q,"Model: ");
2625                                                         if (q) {
2626                                                                 *q = 0;
2627                                                                 q += 7;
2628                                                                 model = q;
2629                                                                 q = strstr(q," Rev: ");
2630                                                                 if (q) {
2631                                                                         *q = 0;
2632                                                                         for (i = 0; i < SIZE(sun_drives); i++) {
2633                                                                                 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2634                                                                                         continue;
2635                                                                                 if (!strstr(model, sun_drives[i].model))
2636                                                                                         continue;
2637                                                                                 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2638                                                                                 p = sun_drives + i;
2639                                                                                 break;
2640                                                                         }
2641                                                                 }
2642                                                         }
2643                                                 }
2644                                         }
2645                                         break;
2646                                 }
2647                         }
2648                         fclose(pfd);
2649                 }
2650         }
2651 #endif
2652         return p;
2653 }
2654
2655 static void
2656 create_sunlabel(void)
2657 {
2658         struct hd_geometry geometry;
2659         unsigned int ndiv;
2660         int i;
2661         unsigned char c;
2662         const struct sun_predefined_drives *p = NULL;
2663
2664         fprintf(stderr,
2665                 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2666                 "until you decide to write them. After that, of course, the previous\n"
2667                 "content won't be recoverable.\n\n"));
2668         sun_other_endian = BB_LITTLE_ENDIAN;
2669         memset(MBRbuffer, 0, sizeof(MBRbuffer));
2670         sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2671         if (!floppy) {
2672                 puts(_("Drive type\n"
2673                  "   ?   auto configure\n"
2674                  "   0   custom (with hardware detected defaults)"));
2675                 for (i = 0; i < SIZE(sun_drives); i++) {
2676                         printf("   %c   %s%s%s\n",
2677                                 i + 'a', sun_drives[i].vendor,
2678                                 (*sun_drives[i].vendor) ? " " : "",
2679                                 sun_drives[i].model);
2680                 }
2681                 while (1) {
2682                         c = read_char(_("Select type (? for auto, 0 for custom): "));
2683                         if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2684                                 p = sun_drives + c - 'a';
2685                                 break;
2686                         } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2687                                 p = sun_drives + c - 'A';
2688                                 break;
2689                         } else if (c == '0') {
2690                                 break;
2691                         } else if (c == '?' && scsi_disk) {
2692                                 p = sun_autoconfigure_scsi();
2693                                 if (!p)
2694                                 printf(_("Autoconfigure failed.\n"));
2695                                 else
2696                                 break;
2697                         }
2698                 }
2699         }
2700         if (!p || floppy) {
2701                 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2702                         heads = geometry.heads;
2703                         sectors = geometry.sectors;
2704                         cylinders = geometry.cylinders;
2705                 } else {
2706                         heads = 0;
2707                         sectors = 0;
2708                         cylinders = 0;
2709                 }
2710                 if (floppy) {
2711                         sunlabel->nacyl = 0;
2712                         sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2713                         sunlabel->rspeed = SUN_SSWAP16(300);
2714                         sunlabel->ilfact = SUN_SSWAP16(1);
2715                         sunlabel->sparecyl = 0;
2716                 } else {
2717                         heads = read_int(1,heads,1024,0,_("Heads"));
2718                         sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2719                 if (cylinders)
2720                         cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2721                 else
2722                         cylinders = read_int(1,0,65535,0,_("Cylinders"));
2723                         sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2724                         sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2725                         sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2726                         sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2727                         sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2728                 }
2729         } else {
2730                 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2731                 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2732                 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2733                 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2734                 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2735                 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2736                 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2737                 sunlabel->ilfact = SUN_SSWAP16(1);
2738                 cylinders = p->ncyl;
2739                 heads = p->ntrks;
2740                 sectors = p->nsect;
2741                 puts(_("You may change all the disk params from the x menu"));
2742         }
2743
2744         snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
2745                 "%s%s%s cyl %d alt %d hd %d sec %d",
2746                 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2747                 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2748                 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2749
2750         sunlabel->ntrks = SUN_SSWAP16(heads);
2751         sunlabel->nsect = SUN_SSWAP16(sectors);
2752         sunlabel->ncyl = SUN_SSWAP16(cylinders);
2753         if (floppy)
2754                 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2755         else {
2756                 if (cylinders * heads * sectors >= 150 * 2048) {
2757                         ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2758                 } else
2759                         ndiv = cylinders * 2 / 3;
2760                 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2761                 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2762                 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2763         }
2764         set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2765         {
2766                 unsigned short *ush = (unsigned short *)sunlabel;
2767                 unsigned short csum = 0;
2768                 while (ush < (unsigned short *)(&sunlabel->csum))
2769                         csum ^= *ush++;
2770                 sunlabel->csum = csum;
2771         }
2772
2773         set_all_unchanged();
2774         set_changed(0);
2775         get_boot(create_empty_sun);
2776 }
2777
2778 static void
2779 toggle_sunflags(int i, unsigned char mask)
2780 {
2781         if (sunlabel->infos[i].flags & mask)
2782                 sunlabel->infos[i].flags &= ~mask;
2783         else
2784                 sunlabel->infos[i].flags |= mask;
2785         set_changed(i);
2786 }
2787
2788 static void
2789 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2790 {
2791         int i, continuous = 1;
2792
2793         *start = 0;
2794         *stop = cylinders * heads * sectors;
2795         for (i = 0; i < partitions; i++) {
2796                 if (sunlabel->partitions[i].num_sectors
2797                  && sunlabel->infos[i].id
2798                  && sunlabel->infos[i].id != WHOLE_DISK) {
2799                         starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2800                         lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2801                         if (continuous) {
2802                                 if (starts[i] == *start)
2803                                         *start += lens[i];
2804                                 else if (starts[i] + lens[i] >= *stop)
2805                                         *stop = starts[i];
2806                                 else
2807                                         continuous = 0;
2808                                         /* There will be probably more gaps
2809                                           than one, so lets check afterwards */
2810                         }
2811                 } else {
2812                         starts[i] = 0;
2813                         lens[i] = 0;
2814                 }
2815         }
2816 }
2817
2818 static uint *verify_sun_starts;
2819
2820 static int
2821 verify_sun_cmp(int *a, int *b)
2822 {
2823         if (*a == -1) return 1;
2824         if (*b == -1) return -1;
2825         if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2826         return -1;
2827 }
2828
2829 static void
2830 verify_sun(void)
2831 {
2832         uint starts[8], lens[8], start, stop;
2833         int i,j,k,starto,endo;
2834         int array[8];
2835
2836         verify_sun_starts = starts;
2837         fetch_sun(starts,lens,&start,&stop);
2838         for (k = 0; k < 7; k++) {
2839                 for (i = 0; i < 8; i++) {
2840                         if (k && (lens[i] % (heads * sectors))) {
2841                                 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2842                         }
2843                         if (lens[i]) {
2844                                 for (j = 0; j < i; j++)
2845                                         if (lens[j]) {
2846                                                 if (starts[j] == starts[i]+lens[i]) {
2847                                                         starts[j] = starts[i]; lens[j] += lens[i];
2848                                                         lens[i] = 0;
2849                                                 } else if (starts[i] == starts[j]+lens[j]){
2850                                                         lens[j] += lens[i];
2851                                                         lens[i] = 0;
2852                                                 } else if (!k) {
2853                                                         if (starts[i] < starts[j]+lens[j]
2854                                                          && starts[j] < starts[i]+lens[i]) {
2855                                                                 starto = starts[i];
2856                                                                 if (starts[j] > starto)
2857                                                                         starto = starts[j];
2858                                                                 endo = starts[i]+lens[i];
2859                                                                 if (starts[j]+lens[j] < endo)
2860                                                                         endo = starts[j]+lens[j];
2861                                                                 printf(_("Partition %d overlaps with others in "
2862                                                                         "sectors %d-%d\n"), i+1, starto, endo);
2863                                                         }
2864                                                 }
2865                                         }
2866                         }
2867                 }
2868         }
2869         for (i = 0; i < 8; i++) {
2870                 if (lens[i])
2871                         array[i] = i;
2872                 else
2873                         array[i] = -1;
2874         }
2875         qsort(array,SIZE(array),sizeof(array[0]),
2876                 (int (*)(const void *,const void *)) verify_sun_cmp);
2877         if (array[0] == -1) {
2878                 printf(_("No partitions defined\n"));
2879                 return;
2880         }
2881         stop = cylinders * heads * sectors;
2882         if (starts[array[0]])
2883                 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2884         for (i = 0; i < 7 && array[i+1] != -1; i++) {
2885                 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2886         }
2887         start = starts[array[i]] + lens[array[i]];
2888         if (start < stop)
2889                 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2890 }
2891
2892 static void
2893 add_sun_partition(int n, int sys)
2894 {
2895         uint start, stop, stop2;
2896         uint starts[8], lens[8];
2897         int whole_disk = 0;
2898
2899         char mesg[256];
2900         int i, first, last;
2901
2902         if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2903                 printf(_("Partition %d is already defined.  Delete "
2904                         "it before re-adding it.\n"), n + 1);
2905                 return;
2906         }
2907
2908         fetch_sun(starts,lens,&start,&stop);
2909         if (stop <= start) {
2910                 if (n == 2)
2911                         whole_disk = 1;
2912                 else {
2913                         printf(_("Other partitions already cover the whole disk.\nDelete "
2914                                    "some/shrink them before retry.\n"));
2915                         return;
2916                 }
2917         }
2918         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2919         while (1) {
2920                 if (whole_disk)
2921                         first = read_int(0, 0, 0, 0, mesg);
2922                 else
2923                         first = read_int(scround(start), scround(stop)+1,
2924                                          scround(stop), 0, mesg);
2925                 if (display_in_cyl_units)
2926                         first *= units_per_sector;
2927                 else
2928                         /* Starting sector has to be properly aligned */
2929                         first = (first + heads * sectors - 1) / (heads * sectors);
2930                 if (n == 2 && first != 0)
2931                         printf("\
2932 It is highly recommended that the third partition covers the whole disk\n\
2933 and is of type `Whole disk'\n");
2934                 /* ewt asks to add: "don't start a partition at cyl 0"
2935                    However, edmundo@rano.demon.co.uk writes:
2936                    "In addition to having a Sun partition table, to be able to
2937                    boot from the disc, the first partition, /dev/sdX1, must
2938                    start at cylinder 0. This means that /dev/sdX1 contains
2939                    the partition table and the boot block, as these are the
2940                    first two sectors of the disc. Therefore you must be
2941                    careful what you use /dev/sdX1 for. In particular, you must
2942                    not use a partition starting at cylinder 0 for Linux swap,
2943                    as that would overwrite the partition table and the boot
2944                    block. You may, however, use such a partition for a UFS
2945                    or EXT2 file system, as these file systems leave the first
2946                    1024 bytes undisturbed. */
2947                 /* On the other hand, one should not use partitions
2948                    starting at block 0 in an md, or the label will
2949                    be trashed. */
2950                 for (i = 0; i < partitions; i++)
2951                         if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
2952                                 break;
2953                 if (i < partitions && !whole_disk) {
2954                         if (n == 2 && !first) {
2955                                 whole_disk = 1;
2956                                 break;
2957                         }
2958                         printf(_("Sector %d is already allocated\n"), first);
2959                 } else
2960                         break;
2961         }
2962         stop = cylinders * heads * sectors;
2963         stop2 = stop;
2964         for (i = 0; i < partitions; i++) {
2965                 if (starts[i] > first && starts[i] < stop)
2966                         stop = starts[i];
2967         }
2968         snprintf(mesg, sizeof(mesg),
2969                 _("Last %s or +size or +sizeM or +sizeK"),
2970                 str_units(SINGULAR));
2971         if (whole_disk)
2972                 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2973                                 0, mesg);
2974         else if (n == 2 && !first)
2975                 last = read_int(scround(first), scround(stop2), scround(stop2),
2976                                 scround(first), mesg);
2977         else
2978                 last = read_int(scround(first), scround(stop), scround(stop),
2979                                 scround(first), mesg);
2980         if (display_in_cyl_units)
2981                 last *= units_per_sector;
2982         if (n == 2 && !first) {
2983                 if (last >= stop2) {
2984                         whole_disk = 1;
2985                         last = stop2;
2986                 } else if (last > stop) {
2987                         printf(_("You haven't covered the whole disk with "
2988                                 "the 3rd partition, but your value\n"
2989                                 "%d %s covers some other partition. "
2990                                 "Your entry has been changed\n"
2991                                 "to %d %s\n"),
2992                                 scround(last), str_units(SINGULAR),
2993                                 scround(stop), str_units(SINGULAR));
2994                         last = stop;
2995                 }
2996         } else if (!whole_disk && last > stop)
2997                 last = stop;
2998
2999         if (whole_disk)
3000                 sys = WHOLE_DISK;
3001         set_sun_partition(n, first, last, sys);
3002 }
3003
3004 static void
3005 sun_delete_partition(int i)
3006 {
3007         unsigned int nsec;
3008
3009         if (i == 2
3010          && sunlabel->infos[i].id == WHOLE_DISK
3011          && !sunlabel->partitions[i].start_cylinder
3012          && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
3013                 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3014                         "consider leaving this\n"
3015                         "partition as Whole disk (5), starting at 0, with %u "
3016                         "sectors\n"), nsec);
3017         sunlabel->infos[i].id = 0;
3018         sunlabel->partitions[i].num_sectors = 0;
3019 }
3020
3021 static void
3022 sun_change_sysid(int i, int sys)
3023 {
3024         if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3025                 read_chars(
3026                         _("It is highly recommended that the partition at offset 0\n"
3027                         "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3028                         "there may destroy your partition table and bootblock.\n"
3029                         "Type YES if you're very sure you would like that partition\n"
3030                         "tagged with 82 (Linux swap): "));
3031                 if (strcmp (line_ptr, _("YES\n")))
3032                         return;
3033         }
3034         switch (sys) {
3035         case SUNOS_SWAP:
3036         case LINUX_SWAP:
3037                 /* swaps are not mountable by default */
3038                 sunlabel->infos[i].flags |= 0x01;
3039                 break;
3040         default:
3041                 /* assume other types are mountable;
3042                    user can change it anyway */
3043                 sunlabel->infos[i].flags &= ~0x01;
3044                 break;
3045         }
3046         sunlabel->infos[i].id = sys;
3047 }
3048
3049 static void
3050 sun_list_table(int xtra)
3051 {
3052         int i, w;
3053
3054         w = strlen(disk_device);
3055         if (xtra)
3056                 printf(
3057                 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3058                 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3059                 "%d extra sects/cyl, interleave %d:1\n"
3060                 "%s\n"
3061                 "Units = %s of %d * 512 bytes\n\n"),
3062                         disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3063                         cylinders, SUN_SSWAP16(sunlabel->nacyl),
3064                         SUN_SSWAP16(sunlabel->pcylcount),
3065                         SUN_SSWAP16(sunlabel->sparecyl),
3066                         SUN_SSWAP16(sunlabel->ilfact),
3067                         (char *)sunlabel,
3068                         str_units(PLURAL), units_per_sector);
3069         else
3070                 printf(
3071         _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3072         "Units = %s of %d * 512 bytes\n\n"),
3073                         disk_device, heads, sectors, cylinders,
3074                         str_units(PLURAL), units_per_sector);
3075
3076         printf(_("%*s Flag    Start       End    Blocks   Id  System\n"),
3077                 w + 1, _("Device"));
3078         for (i = 0 ; i < partitions; i++) {
3079                 if (sunlabel->partitions[i].num_sectors) {
3080                         uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3081                         uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
3082                         printf("%s %c%c %9ld %9ld %9ld%c  %2x  %s\n",
3083                                 partname(disk_device, i+1, w),                  /* device */
3084                                 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',  /* flags */
3085                                 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3086                                 (long) scround(start),                          /* start */
3087                                 (long) scround(start+len),                      /* end */
3088                                 (long) len / 2, len & 1 ? '+' : ' ',            /* odd flag on end */
3089                                 sunlabel->infos[i].id,                          /* type id */
3090                                 partition_type(sunlabel->infos[i].id));         /* type name */
3091                 }
3092         }
3093 }
3094
3095 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3096
3097 static void
3098 sun_set_alt_cyl(void)
3099 {
3100         sunlabel->nacyl =
3101                 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3102                                 _("Number of alternate cylinders")));
3103 }
3104
3105 static void
3106 sun_set_ncyl(int cyl)
3107 {
3108         sunlabel->ncyl = SUN_SSWAP16(cyl);
3109 }
3110
3111 static void
3112 sun_set_xcyl(void)
3113 {
3114         sunlabel->sparecyl =
3115                 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3116                                 _("Extra sectors per cylinder")));
3117 }
3118
3119 static void
3120 sun_set_ilfact(void)
3121 {
3122         sunlabel->ilfact =
3123                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3124                                 _("Interleave factor")));
3125 }
3126
3127 static void
3128 sun_set_rspeed(void)
3129 {
3130         sunlabel->rspeed =
3131                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3132                                 _("Rotation speed (rpm)")));
3133 }
3134
3135 static void
3136 sun_set_pcylcount(void)
3137 {
3138         sunlabel->pcylcount =
3139                 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3140                                 _("Number of physical cylinders")));
3141 }
3142 #endif /* CONFIG_FEATURE_FDISK_ADVANCED */
3143
3144 static void
3145 sun_write_table(void)
3146 {
3147         unsigned short *ush = (unsigned short *)sunlabel;
3148         unsigned short csum = 0;
3149
3150         while (ush < (unsigned short *)(&sunlabel->csum))
3151                 csum ^= *ush++;
3152         sunlabel->csum = csum;
3153         if (lseek(fd, 0, SEEK_SET) < 0)
3154                 fdisk_fatal(unable_to_seek);
3155         if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3156                 fdisk_fatal(unable_to_write);
3157 }
3158 #endif /* SUN_LABEL */
3159
3160 /* DOS partition types */
3161
3162 static const struct systypes i386_sys_types[] = {
3163         { "\x00" "Empty" },
3164         { "\x01" "FAT12" },
3165         { "\x04" "FAT16 <32M" },
3166         { "\x05" "Extended" },         /* DOS 3.3+ extended partition */
3167         { "\x06" "FAT16" },            /* DOS 16-bit >=32M */
3168         { "\x07" "HPFS/NTFS" },        /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3169         { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3170         { "\x0b" "Win95 FAT32" },
3171         { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3172         { "\x0e" "Win95 FAT16 (LBA)" },
3173         { "\x0f" "Win95 Ext'd (LBA)" },
3174         { "\x11" "Hidden FAT12" },
3175         { "\x12" "Compaq diagnostics" },
3176         { "\x14" "Hidden FAT16 <32M" },
3177         { "\x16" "Hidden FAT16" },
3178         { "\x17" "Hidden HPFS/NTFS" },
3179         { "\x1b" "Hidden Win95 FAT32" },
3180         { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3181         { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3182         { "\x3c" "PartitionMagic recovery" },
3183         { "\x41" "PPC PReP Boot" },
3184         { "\x42" "SFS" },
3185         { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3186         { "\x80" "Old Minix" },        /* Minix 1.4a and earlier */
3187         { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3188         { "\x82" "Linux swap" },       /* also Solaris */
3189         { "\x83" "Linux" },
3190         { "\x84" "OS/2 hidden C: drive" },
3191         { "\x85" "Linux extended" },
3192         { "\x86" "NTFS volume set" },
3193         { "\x87" "NTFS volume set" },
3194         { "\x8e" "Linux LVM" },
3195         { "\x9f" "BSD/OS" },           /* BSDI */
3196         { "\xa0" "IBM Thinkpad hibernation" },
3197         { "\xa5" "FreeBSD" },          /* various BSD flavours */
3198         { "\xa6" "OpenBSD" },
3199         { "\xa8" "Darwin UFS" },
3200         { "\xa9" "NetBSD" },
3201         { "\xab" "Darwin boot" },
3202         { "\xb7" "BSDI fs" },
3203         { "\xb8" "BSDI swap" },
3204         { "\xbe" "Solaris boot" },
3205         { "\xeb" "BeOS fs" },
3206         { "\xee" "EFI GPT" },          /* Intel EFI GUID Partition Table */
3207         { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3208         { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3209         { "\xf2" "DOS secondary" },    /* DOS 3.3+ secondary */
3210         { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3211                                                 autodetect using persistent
3212                                                 superblock */
3213 #ifdef CONFIG_WEIRD_PARTITION_TYPES
3214         { "\x02" "XENIX root" },
3215         { "\x03" "XENIX usr" },
3216         { "\x08" "AIX" },              /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3217         { "\x09" "AIX bootable" },     /* AIX data or Coherent */
3218         { "\x10" "OPUS" },
3219         { "\x18" "AST SmartSleep" },
3220         { "\x24" "NEC DOS" },
3221         { "\x39" "Plan 9" },
3222         { "\x40" "Venix 80286" },
3223         { "\x4d" "QNX4.x" },
3224         { "\x4e" "QNX4.x 2nd part" },
3225         { "\x4f" "QNX4.x 3rd part" },
3226         { "\x50" "OnTrack DM" },
3227         { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3228         { "\x52" "CP/M" },             /* CP/M or Microport SysV/AT */
3229         { "\x53" "OnTrack DM6 Aux3" },
3230         { "\x54" "OnTrackDM6" },
3231         { "\x55" "EZ-Drive" },
3232         { "\x56" "Golden Bow" },
3233         { "\x5c" "Priam Edisk" },
3234         { "\x61" "SpeedStor" },
3235         { "\x64" "Novell Netware 286" },
3236         { "\x65" "Novell Netware 386" },
3237         { "\x70" "DiskSecure Multi-Boot" },
3238         { "\x75" "PC/IX" },
3239         { "\x93" "Amoeba" },
3240         { "\x94" "Amoeba BBT" },       /* (bad block table) */
3241         { "\xa7" "NeXTSTEP" },
3242         { "\xbb" "Boot Wizard hidden" },
3243         { "\xc1" "DRDOS/sec (FAT-12)" },
3244         { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3245         { "\xc6" "DRDOS/sec (FAT-16)" },
3246         { "\xc7" "Syrinx" },
3247         { "\xda" "Non-FS data" },
3248         { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
3249                                         Concurrent DOS or CTOS */
3250         { "\xde" "Dell Utility" },     /* Dell PowerEdge Server utilities */
3251         { "\xdf" "BootIt" },           /* BootIt EMBRM */
3252         { "\xe1" "DOS access" },       /* DOS access or SpeedStor 12-bit FAT
3253                                         extended partition */
3254         { "\xe3" "DOS R/O" },          /* DOS R/O or SpeedStor */
3255         { "\xe4" "SpeedStor" },        /* SpeedStor 16-bit FAT extended
3256                                         partition < 1024 cyl. */
3257         { "\xf1" "SpeedStor" },
3258         { "\xf4" "SpeedStor" },        /* SpeedStor large partition */
3259         { "\xfe" "LANstep" },          /* SpeedStor >1024 cyl. or LANstep */
3260         { "\xff" "BBT" },              /* Xenix Bad Block Table */
3261 #endif
3262         { 0 }
3263 };
3264
3265
3266
3267 /* A valid partition table sector ends in 0x55 0xaa */
3268 static unsigned int
3269 part_table_flag(const char *b)
3270 {
3271         return ((uint) b[510]) + (((uint) b[511]) << 8);
3272 }
3273
3274
3275 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3276 static void
3277 write_part_table_flag(char *b)
3278 {
3279         b[510] = 0x55;
3280         b[511] = 0xaa;
3281 }
3282
3283 /* start_sect and nr_sects are stored little endian on all machines */
3284 /* moreover, they are not aligned correctly */
3285 static void
3286 store4_little_endian(unsigned char *cp, unsigned int val)
3287 {
3288         cp[0] = (val & 0xff);
3289         cp[1] = ((val >> 8) & 0xff);
3290         cp[2] = ((val >> 16) & 0xff);
3291         cp[3] = ((val >> 24) & 0xff);
3292 }
3293 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3294
3295 static unsigned int
3296 read4_little_endian(const unsigned char *cp)
3297 {
3298         return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3299                 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3300 }
3301
3302 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3303 static void
3304 set_start_sect(struct partition *p, unsigned int start_sect)
3305 {
3306         store4_little_endian(p->start4, start_sect);
3307 }
3308 #endif
3309
3310 static int32_t
3311 get_start_sect(const struct partition *p)
3312 {
3313         return read4_little_endian(p->start4);
3314 }
3315
3316 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3317 static void
3318 set_nr_sects(struct partition *p, int32_t nr_sects)
3319 {
3320         store4_little_endian(p->size4, nr_sects);
3321 }
3322 #endif
3323
3324 static int32_t
3325 get_nr_sects(const struct partition *p)
3326 {
3327         return read4_little_endian(p->size4);
3328 }
3329
3330 /* normally O_RDWR, -l option gives O_RDONLY */
3331 static int type_open = O_RDWR;
3332
3333
3334 static int ext_index;               /* the prime extended partition */
3335 static int listing;                    /* no aborts for fdisk -l */
3336 static int dos_compatible_flag = ~0;
3337 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3338 static int dos_changed;
3339 static int nowarn;            /* no warnings for fdisk -l/-s */
3340 #endif
3341
3342
3343
3344 static uint user_cylinders, user_heads, user_sectors;
3345 static uint pt_heads, pt_sectors;
3346 static uint kern_heads, kern_sectors;
3347
3348 static off_t extended_offset;            /* offset of link pointers */
3349
3350 static unsigned long long total_number_of_sectors;
3351
3352
3353 static jmp_buf listingbuf;
3354
3355 static void fdisk_fatal(enum failure why)
3356 {
3357         const char *message;
3358
3359         if (listing) {
3360                 close(fd);
3361                 longjmp(listingbuf, 1);
3362         }
3363
3364         switch (why) {
3365         case unable_to_open:
3366                 message = "Unable to open %s\n";
3367                 break;
3368         case unable_to_read:
3369                 message = "Unable to read %s\n";
3370                 break;
3371         case unable_to_seek:
3372                 message = "Unable to seek on %s\n";
3373                 break;
3374         case unable_to_write:
3375                 message = "Unable to write %s\n";
3376                 break;
3377         case ioctl_error:
3378                 message = "BLKGETSIZE ioctl failed on %s\n";
3379                 break;
3380         default:
3381                 message = "Fatal error\n";
3382         }
3383
3384         fputc('\n', stderr);
3385         fprintf(stderr, message, disk_device);
3386         exit(1);
3387 }
3388
3389 static void
3390 seek_sector(off_t secno)
3391 {
3392         off_t offset = secno * sector_size;
3393         if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
3394                 fdisk_fatal(unable_to_seek);
3395 }
3396
3397 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3398 static void
3399 write_sector(off_t secno, char *buf)
3400 {
3401         seek_sector(secno);
3402         if (write(fd, buf, sector_size) != sector_size)
3403                 fdisk_fatal(unable_to_write);
3404 }
3405 #endif
3406
3407 /* Allocate a buffer and read a partition table sector */
3408 static void
3409 read_pte(struct pte *pe, off_t offset)
3410 {
3411         pe->offset = offset;
3412         pe->sectorbuffer = (char *) xmalloc(sector_size);
3413         seek_sector(offset);
3414         if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3415                 fdisk_fatal(unable_to_read);
3416 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3417         pe->changed = 0;
3418 #endif
3419         pe->part_table = pe->ext_pointer = NULL;
3420 }
3421
3422 static unsigned int
3423 get_partition_start(const struct pte *pe)
3424 {
3425         return pe->offset + get_start_sect(pe->part_table);
3426 }
3427
3428 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3429 /*
3430  * Avoid warning about DOS partitions when no DOS partition was changed.
3431  * Here a heuristic "is probably dos partition".
3432  * We might also do the opposite and warn in all cases except
3433  * for "is probably nondos partition".
3434  */
3435 static int
3436 is_dos_partition(int t)
3437 {
3438         return (t == 1 || t == 4 || t == 6 ||
3439                 t == 0x0b || t == 0x0c || t == 0x0e ||
3440                 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3441                 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3442                 t == 0xc1 || t == 0xc4 || t == 0xc6);
3443 }
3444
3445 static void
3446 menu(void)
3447 {
3448 #ifdef CONFIG_FEATURE_SUN_LABEL
3449         if (label_sun == current_label_type) {
3450                 puts(_("Command action"));
3451                 puts(_("\ta\ttoggle a read only flag"));           /* sun */
3452                 puts(_("\tb\tedit bsd disklabel"));
3453                 puts(_("\tc\ttoggle the mountable flag"));         /* sun */
3454                 puts(_("\td\tdelete a partition"));
3455                 puts(_("\tl\tlist known partition types"));
3456                 puts(_("\tm\tprint this menu"));
3457                 puts(_("\tn\tadd a new partition"));
3458                 puts(_("\to\tcreate a new empty DOS partition table"));
3459                 puts(_("\tp\tprint the partition table"));
3460                 puts(_("\tq\tquit without saving changes"));
3461                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3462                 puts(_("\tt\tchange a partition's system id"));
3463                 puts(_("\tu\tchange display/entry units"));
3464                 puts(_("\tv\tverify the partition table"));
3465                 puts(_("\tw\twrite table to disk and exit"));
3466 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3467                 puts(_("\tx\textra functionality (experts only)"));
3468 #endif
3469         } else
3470 #endif
3471 #ifdef CONFIG_FEATURE_SGI_LABEL
3472         if (label_sgi == current_label_type) {
3473                 puts(_("Command action"));
3474                 puts(_("\ta\tselect bootable partition"));    /* sgi flavour */
3475                 puts(_("\tb\tedit bootfile entry"));          /* sgi */
3476                 puts(_("\tc\tselect sgi swap partition"));    /* sgi flavour */
3477                 puts(_("\td\tdelete a partition"));
3478                 puts(_("\tl\tlist known partition types"));
3479                 puts(_("\tm\tprint this menu"));
3480                 puts(_("\tn\tadd a new partition"));
3481                 puts(_("\to\tcreate a new empty DOS partition table"));
3482                 puts(_("\tp\tprint the partition table"));
3483                 puts(_("\tq\tquit without saving changes"));
3484                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3485                 puts(_("\tt\tchange a partition's system id"));
3486                 puts(_("\tu\tchange display/entry units"));
3487                 puts(_("\tv\tverify the partition table"));
3488                 puts(_("\tw\twrite table to disk and exit"));
3489         } else
3490 #endif
3491 #ifdef CONFIG_FEATURE_AIX_LABEL
3492         if (label_aix == current_label_type) {
3493                 puts(_("Command action"));
3494                 puts(_("\tm\tprint this menu"));
3495                 puts(_("\to\tcreate a new empty DOS partition table"));
3496                 puts(_("\tq\tquit without saving changes"));
3497                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3498         } else
3499 #endif
3500         {
3501                 puts(_("Command action"));
3502                 puts(_("\ta\ttoggle a bootable flag"));
3503                 puts(_("\tb\tedit bsd disklabel"));
3504                 puts(_("\tc\ttoggle the dos compatibility flag"));
3505                 puts(_("\td\tdelete a partition"));
3506                 puts(_("\tl\tlist known partition types"));
3507                 puts(_("\tm\tprint this menu"));
3508                 puts(_("\tn\tadd a new partition"));
3509                 puts(_("\to\tcreate a new empty DOS partition table"));
3510                 puts(_("\tp\tprint the partition table"));
3511                 puts(_("\tq\tquit without saving changes"));
3512                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3513                 puts(_("\tt\tchange a partition's system id"));
3514                 puts(_("\tu\tchange display/entry units"));
3515                 puts(_("\tv\tverify the partition table"));
3516                 puts(_("\tw\twrite table to disk and exit"));
3517 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3518                 puts(_("\tx\textra functionality (experts only)"));
3519 #endif
3520         }
3521 }
3522 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3523
3524
3525 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3526 static void
3527 xmenu(void)
3528 {
3529 #ifdef CONFIG_FEATURE_SUN_LABEL
3530         if (label_sun == current_label_type) {
3531         puts(_("Command action"));
3532         puts(_("\ta\tchange number of alternate cylinders"));      /*sun*/
3533         puts(_("\tc\tchange number of cylinders"));
3534         puts(_("\td\tprint the raw data in the partition table"));
3535         puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3536         puts(_("\th\tchange number of heads"));
3537         puts(_("\ti\tchange interleave factor"));                  /*sun*/
3538         puts(_("\to\tchange rotation speed (rpm)"));               /*sun*/
3539         puts(_("\tm\tprint this menu"));
3540         puts(_("\tp\tprint the partition table"));
3541         puts(_("\tq\tquit without saving changes"));
3542         puts(_("\tr\treturn to main menu"));
3543         puts(_("\ts\tchange number of sectors/track"));
3544         puts(_("\tv\tverify the partition table"));
3545         puts(_("\tw\twrite table to disk and exit"));
3546         puts(_("\ty\tchange number of physical cylinders"));       /*sun*/
3547         }  else
3548 #endif
3549 #ifdef CONFIG_FEATURE_SGI_LABEL
3550         if (label_sgi == current_label_type) {
3551                 puts(_("Command action"));
3552                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3553                 puts(_("\tc\tchange number of cylinders"));
3554                 puts(_("\td\tprint the raw data in the partition table"));
3555                 puts(_("\te\tlist extended partitions"));          /* !sun */
3556                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3557                 puts(_("\th\tchange number of heads"));
3558                 puts(_("\tm\tprint this menu"));
3559                 puts(_("\tp\tprint the partition table"));
3560                 puts(_("\tq\tquit without saving changes"));
3561                 puts(_("\tr\treturn to main menu"));
3562                 puts(_("\ts\tchange number of sectors/track"));
3563                 puts(_("\tv\tverify the partition table"));
3564                 puts(_("\tw\twrite table to disk and exit"));
3565         } else
3566 #endif
3567 #ifdef CONFIG_FEATURE_AIX_LABEL
3568         if (label_aix == current_label_type) {
3569                 puts(_("Command action"));
3570                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3571                 puts(_("\tc\tchange number of cylinders"));
3572                 puts(_("\td\tprint the raw data in the partition table"));
3573                 puts(_("\te\tlist extended partitions"));          /* !sun */
3574                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3575                 puts(_("\th\tchange number of heads"));
3576                 puts(_("\tm\tprint this menu"));
3577                 puts(_("\tp\tprint the partition table"));
3578                 puts(_("\tq\tquit without saving changes"));
3579                 puts(_("\tr\treturn to main menu"));
3580                 puts(_("\ts\tchange number of sectors/track"));
3581                 puts(_("\tv\tverify the partition table"));
3582                 puts(_("\tw\twrite table to disk and exit"));
3583         }  else
3584 #endif
3585         {
3586                 puts(_("Command action"));
3587                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3588                 puts(_("\tc\tchange number of cylinders"));
3589                 puts(_("\td\tprint the raw data in the partition table"));
3590                 puts(_("\te\tlist extended partitions"));          /* !sun */
3591                 puts(_("\tf\tfix partition order"));               /* !sun, !aix, !sgi */
3592 #ifdef CONFIG_FEATURE_SGI_LABEL
3593                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3594 #endif
3595                 puts(_("\th\tchange number of heads"));
3596                 puts(_("\tm\tprint this menu"));
3597                 puts(_("\tp\tprint the partition table"));
3598                 puts(_("\tq\tquit without saving changes"));
3599                 puts(_("\tr\treturn to main menu"));
3600                 puts(_("\ts\tchange number of sectors/track"));
3601                 puts(_("\tv\tverify the partition table"));
3602                 puts(_("\tw\twrite table to disk and exit"));
3603         }
3604 }
3605 #endif /* ADVANCED mode */
3606
3607 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3608 static const struct systypes *
3609 get_sys_types(void)
3610 {
3611         return (
3612 #ifdef CONFIG_FEATURE_SUN_LABEL
3613                 label_sun == current_label_type ? sun_sys_types :
3614 #endif
3615 #ifdef CONFIG_FEATURE_SGI_LABEL
3616                 label_sgi == current_label_type ? sgi_sys_types :
3617 #endif
3618                 i386_sys_types);
3619 }
3620 #else
3621 #define get_sys_types() i386_sys_types
3622 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3623
3624 static const char *partition_type(unsigned char type)
3625 {
3626         int i;
3627         const struct systypes *types = get_sys_types();
3628
3629         for (i = 0; types[i].name; i++)
3630                 if ((unsigned char )types[i].name[0] == type)
3631                         return types[i].name + 1;
3632
3633         return _("Unknown");
3634 }
3635
3636
3637 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3638 static int
3639 get_sysid(int i)
3640 {
3641         return (
3642 #ifdef CONFIG_FEATURE_SUN_LABEL
3643                 label_sun == current_label_type ? sunlabel->infos[i].id :
3644 #endif
3645 #ifdef CONFIG_FEATURE_SGI_LABEL
3646                 label_sgi == current_label_type ? sgi_get_sysid(i) :
3647 #endif
3648                 ptes[i].part_table->sys_ind);
3649 }
3650
3651 void list_types(const struct systypes *sys)
3652 {
3653         uint last[4], done = 0, next = 0, size;
3654         int i;
3655
3656         for (i = 0; sys[i].name; i++);
3657         size = i;
3658
3659         for (i = 3; i >= 0; i--)
3660                 last[3 - i] = done += (size + i - done) / (i + 1);
3661         i = done = 0;
3662
3663         do {
3664                 printf("%c%2x  %-15.15s", i ? ' ' : '\n',
3665                         (unsigned char)sys[next].name[0],
3666                         partition_type((unsigned char)sys[next].name[0]));
3667                 next = last[i++] + done;
3668                 if (i > 3 || next >= last[i]) {
3669                         i = 0;
3670                         next = ++done;
3671                 }
3672         } while (done < last[0]);
3673         putchar('\n');
3674 }
3675 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3676
3677 static int
3678 is_cleared_partition(const struct partition *p)
3679 {
3680         return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3681                  p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3682                  get_start_sect(p) || get_nr_sects(p));
3683 }
3684
3685 static void
3686 clear_partition(struct partition *p)
3687 {
3688         if (!p)
3689                 return;
3690         memset(p, 0, sizeof(struct partition));
3691 }
3692
3693 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3694 static void
3695 set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3696 {
3697         struct partition *p;
3698         off_t offset;
3699
3700         if (doext) {
3701                 p = ptes[i].ext_pointer;
3702                 offset = extended_offset;
3703         } else {
3704                 p = ptes[i].part_table;
3705                 offset = ptes[i].offset;
3706         }
3707         p->boot_ind = 0;
3708         p->sys_ind = sysid;
3709         set_start_sect(p, start - offset);
3710         set_nr_sects(p, stop - start + 1);
3711         if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3712                 start = heads*sectors*1024 - 1;
3713         set_hsc(p->head, p->sector, p->cyl, start);
3714         if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3715                 stop = heads*sectors*1024 - 1;
3716         set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3717         ptes[i].changed = 1;
3718 }
3719 #endif
3720
3721 static int
3722 test_c(const char **m, const char *mesg)
3723 {
3724         int val = 0;
3725         if (!*m)
3726                 fprintf(stderr, _("You must set"));
3727         else {
3728                 fprintf(stderr, " %s", *m);
3729                 val = 1;
3730         }
3731         *m = mesg;
3732         return val;
3733 }
3734
3735 static int
3736 warn_geometry(void)
3737 {
3738         const char *m = NULL;
3739         int prev = 0;
3740
3741         if (!heads)
3742                 prev = test_c(&m, _("heads"));
3743         if (!sectors)
3744                 prev = test_c(&m, _("sectors"));
3745         if (!cylinders)
3746                 prev = test_c(&m, _("cylinders"));
3747         if (!m)
3748                 return 0;
3749
3750         fprintf(stderr, "%s%s.\n"
3751 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3752                         "You can do this from the extra functions menu.\n"
3753 #endif
3754                 , prev ? _(" and ") : " ", m);
3755
3756         return 1;
3757 }
3758
3759 static void update_units(void)
3760 {
3761         int cyl_units = heads * sectors;
3762
3763         if (display_in_cyl_units && cyl_units)
3764                 units_per_sector = cyl_units;
3765         else
3766                 units_per_sector = 1;   /* in sectors */
3767 }
3768
3769 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3770 static void
3771 warn_cylinders(void)
3772 {
3773         if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
3774                 fprintf(stderr, _("\n"
3775 "The number of cylinders for this disk is set to %d.\n"
3776 "There is nothing wrong with that, but this is larger than 1024,\n"
3777 "and could in certain setups cause problems with:\n"
3778 "1) software that runs at boot time (e.g., old versions of LILO)\n"
3779 "2) booting and partitioning software from other OSs\n"
3780 "   (e.g., DOS FDISK, OS/2 FDISK)\n"),
3781                         cylinders);
3782 }
3783 #endif
3784
3785 static void
3786 read_extended(int ext)
3787 {
3788         int i;
3789         struct pte *pex;
3790         struct partition *p, *q;
3791
3792         ext_index = ext;
3793         pex = &ptes[ext];
3794         pex->ext_pointer = pex->part_table;
3795
3796         p = pex->part_table;
3797         if (!get_start_sect(p)) {
3798                 fprintf(stderr,
3799                         _("Bad offset in primary extended partition\n"));
3800                 return;
3801         }
3802
3803         while (IS_EXTENDED(p->sys_ind)) {
3804                 struct pte *pe = &ptes[partitions];
3805
3806                 if (partitions >= MAXIMUM_PARTS) {
3807                         /* This is not a Linux restriction, but
3808                            this program uses arrays of size MAXIMUM_PARTS.
3809                            Do not try to `improve' this test. */
3810                         struct pte *pre = &ptes[partitions-1];
3811 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3812                         fprintf(stderr,
3813                                 _("Warning: deleting partitions after %d\n"),
3814                                 partitions);
3815                         pre->changed = 1;
3816 #endif
3817                         clear_partition(pre->ext_pointer);
3818                         return;
3819                 }
3820
3821                 read_pte(pe, extended_offset + get_start_sect(p));
3822
3823                 if (!extended_offset)
3824                         extended_offset = get_start_sect(p);
3825
3826                 q = p = pt_offset(pe->sectorbuffer, 0);
3827                 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3828                         if (IS_EXTENDED(p->sys_ind)) {
3829                                 if (pe->ext_pointer)
3830                                         fprintf(stderr,
3831                                                 _("Warning: extra link "
3832                                                   "pointer in partition table"
3833                                                   " %d\n"), partitions + 1);
3834                                 else
3835                                         pe->ext_pointer = p;
3836                         } else if (p->sys_ind) {
3837                                 if (pe->part_table)
3838                                         fprintf(stderr,
3839                                                 _("Warning: ignoring extra "
3840                                                   "data in partition table"
3841                                                   " %d\n"), partitions + 1);
3842                                 else
3843                                         pe->part_table = p;
3844                         }
3845                 }
3846
3847                 /* very strange code here... */
3848                 if (!pe->part_table) {
3849                         if (q != pe->ext_pointer)
3850                                 pe->part_table = q;
3851                         else
3852                                 pe->part_table = q + 1;
3853                 }
3854                 if (!pe->ext_pointer) {
3855                         if (q != pe->part_table)
3856                                 pe->ext_pointer = q;
3857                         else
3858                                 pe->ext_pointer = q + 1;
3859                 }
3860
3861                 p = pe->ext_pointer;
3862                 partitions++;
3863         }
3864
3865 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3866         /* remove empty links */
3867  remove:
3868         for (i = 4; i < partitions; i++) {
3869                 struct pte *pe = &ptes[i];
3870
3871                 if (!get_nr_sects(pe->part_table) &&
3872                         (partitions > 5 || ptes[4].part_table->sys_ind)) {
3873                         printf("omitting empty partition (%d)\n", i+1);
3874                         delete_partition(i);
3875                         goto remove;    /* numbering changed */
3876                 }
3877         }
3878 #endif
3879 }
3880
3881 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3882 static void
3883 create_doslabel(void)
3884 {
3885         int i;
3886
3887         fprintf(stderr,
3888         _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3889           "until you decide to write them. After that, of course, the previous\n"
3890           "content won't be recoverable.\n\n"));
3891
3892         current_label_type = label_dos;
3893
3894 #ifdef CONFIG_FEATURE_OSF_LABEL
3895         possibly_osf_label = 0;
3896 #endif
3897         partitions = 4;
3898
3899         for (i = 510-64; i < 510; i++)
3900                 MBRbuffer[i] = 0;
3901         write_part_table_flag(MBRbuffer);
3902         extended_offset = 0;
3903         set_all_unchanged();
3904         set_changed(0);
3905         get_boot(create_empty_dos);
3906 }
3907 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3908
3909 static void
3910 get_sectorsize(void)
3911 {
3912         if (!user_set_sector_size) {
3913                 int arg;
3914                 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3915                         sector_size = arg;
3916                 if (sector_size != DEFAULT_SECTOR_SIZE)
3917                         printf(_("Note: sector size is %d (not %d)\n"),
3918                                    sector_size, DEFAULT_SECTOR_SIZE);
3919         }
3920 }
3921
3922 static void
3923 get_kernel_geometry(void)
3924 {
3925         struct hd_geometry geometry;
3926
3927         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3928                 kern_heads = geometry.heads;
3929                 kern_sectors = geometry.sectors;
3930                 /* never use geometry.cylinders - it is truncated */
3931         }
3932 }
3933
3934 static void
3935 get_partition_table_geometry(void)
3936 {
3937         const unsigned char *bufp = (const unsigned char *)MBRbuffer;
3938         struct partition *p;
3939         int i, h, s, hh, ss;
3940         int first = 1;
3941         int bad = 0;
3942
3943         if (!(valid_part_table_flag((char*)bufp)))
3944                 return;
3945
3946         hh = ss = 0;
3947         for (i = 0; i < 4; i++) {
3948                 p = pt_offset(bufp, i);
3949                 if (p->sys_ind != 0) {
3950                         h = p->end_head + 1;
3951                         s = (p->end_sector & 077);
3952                         if (first) {
3953                                 hh = h;
3954                                 ss = s;
3955                                 first = 0;
3956                         } else if (hh != h || ss != s)
3957                                 bad = 1;
3958                 }
3959         }
3960
3961         if (!first && !bad) {
3962                 pt_heads = hh;
3963                 pt_sectors = ss;
3964         }
3965 }
3966
3967 static void
3968 get_geometry(void)
3969 {
3970         int sec_fac;
3971         unsigned long long bytes;       /* really u64 */
3972
3973         get_sectorsize();
3974         sec_fac = sector_size / 512;
3975 #ifdef CONFIG_FEATURE_SUN_LABEL
3976         guess_device_type();
3977 #endif
3978         heads = cylinders = sectors = 0;
3979         kern_heads = kern_sectors = 0;
3980         pt_heads = pt_sectors = 0;
3981
3982         get_kernel_geometry();
3983         get_partition_table_geometry();
3984
3985         heads = user_heads ? user_heads :
3986                 pt_heads ? pt_heads :
3987                 kern_heads ? kern_heads : 255;
3988         sectors = user_sectors ? user_sectors :
3989                 pt_sectors ? pt_sectors :
3990                 kern_sectors ? kern_sectors : 63;
3991         if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3992                 /* got bytes */
3993         } else {
3994                 unsigned long longsectors;
3995
3996         if (ioctl(fd, BLKGETSIZE, &longsectors))
3997                 longsectors = 0;
3998                         bytes = ((unsigned long long) longsectors) << 9;
3999         }
4000
4001         total_number_of_sectors = (bytes >> 9);
4002
4003         sector_offset = 1;
4004         if (dos_compatible_flag)
4005                 sector_offset = sectors;
4006
4007         cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
4008         if (!cylinders)
4009                 cylinders = user_cylinders;
4010 }
4011
4012 /*
4013  * Read MBR.  Returns:
4014  *   -1: no 0xaa55 flag present (possibly entire disk BSD)
4015  *    0: found or created label
4016  *    1: I/O error
4017  */
4018 static int
4019 get_boot(enum action what)
4020 {
4021         int i;
4022
4023         partitions = 4;
4024
4025         for (i = 0; i < 4; i++) {
4026                 struct pte *pe = &ptes[i];
4027
4028                 pe->part_table = pt_offset(MBRbuffer, i);
4029                 pe->ext_pointer = NULL;
4030                 pe->offset = 0;
4031                 pe->sectorbuffer = MBRbuffer;
4032 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4033                 pe->changed = (what == create_empty_dos);
4034 #endif
4035         }
4036
4037 #ifdef CONFIG_FEATURE_SUN_LABEL
4038         if (what == create_empty_sun && check_sun_label())
4039                 return 0;
4040 #endif
4041
4042         memset(MBRbuffer, 0, 512);
4043
4044 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4045         if (what == create_empty_dos)
4046                 goto got_dos_table;             /* skip reading disk */
4047
4048         if ((fd = open(disk_device, type_open)) < 0) {
4049                 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4050                         if (what == try_only)
4051                                 return 1;
4052                         fdisk_fatal(unable_to_open);
4053                 } else
4054                         printf(_("You will not be able to write "
4055                                 "the partition table.\n"));
4056         }
4057
4058         if (512 != read(fd, MBRbuffer, 512)) {
4059                 if (what == try_only)
4060                         return 1;
4061                 fdisk_fatal(unable_to_read);
4062         }
4063 #else
4064         if ((fd = open(disk_device, O_RDONLY)) < 0)
4065                 return 1;
4066         if (512 != read(fd, MBRbuffer, 512))
4067                 return 1;
4068 #endif
4069
4070         get_geometry();
4071
4072         update_units();
4073
4074 #ifdef CONFIG_FEATURE_SUN_LABEL
4075         if (check_sun_label())
4076                 return 0;
4077 #endif
4078
4079 #ifdef CONFIG_FEATURE_SGI_LABEL
4080         if (check_sgi_label())
4081                 return 0;
4082 #endif
4083
4084 #ifdef CONFIG_FEATURE_AIX_LABEL
4085         if (check_aix_label())
4086                 return 0;
4087 #endif
4088
4089 #ifdef CONFIG_FEATURE_OSF_LABEL
4090         if (check_osf_label()) {
4091                 possibly_osf_label = 1;
4092                 if (!valid_part_table_flag(MBRbuffer)) {
4093                         current_label_type = label_osf;
4094                         return 0;
4095                 }
4096                 printf(_("This disk has both DOS and BSD magic.\n"
4097                          "Give the 'b' command to go to BSD mode.\n"));
4098         }
4099 #endif
4100
4101 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4102  got_dos_table:
4103 #endif
4104
4105         if (!valid_part_table_flag(MBRbuffer)) {
4106 #ifndef CONFIG_FEATURE_FDISK_WRITABLE
4107                 return -1;
4108 #else
4109                 switch (what) {
4110                 case fdisk:
4111                         fprintf(stderr,
4112                                 _("Device contains neither a valid DOS "
4113                                   "partition table, nor Sun, SGI or OSF "
4114                                   "disklabel\n"));
4115 #ifdef __sparc__
4116 #ifdef CONFIG_FEATURE_SUN_LABEL
4117                         create_sunlabel();
4118 #endif
4119 #else
4120                         create_doslabel();
4121 #endif
4122                         return 0;
4123                 case try_only:
4124                         return -1;
4125                 case create_empty_dos:
4126 #ifdef CONFIG_FEATURE_SUN_LABEL
4127                 case create_empty_sun:
4128 #endif
4129                         break;
4130                 default:
4131                         fprintf(stderr, _("Internal error\n"));
4132                         exit(1);
4133                 }
4134 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4135         }
4136
4137 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4138         warn_cylinders();
4139 #endif
4140         warn_geometry();
4141
4142         for (i = 0; i < 4; i++) {
4143                 struct pte *pe = &ptes[i];
4144
4145                 if (IS_EXTENDED(pe->part_table->sys_ind)) {
4146                         if (partitions != 4)
4147                                 fprintf(stderr, _("Ignoring extra extended "
4148                                         "partition %d\n"), i + 1);
4149                         else
4150                                 read_extended(i);
4151                 }
4152         }
4153
4154         for (i = 3; i < partitions; i++) {
4155                 struct pte *pe = &ptes[i];
4156
4157                 if (!valid_part_table_flag(pe->sectorbuffer)) {
4158                         fprintf(stderr,
4159                                 _("Warning: invalid flag 0x%04x of partition "
4160                                 "table %d will be corrected by w(rite)\n"),
4161                                 part_table_flag(pe->sectorbuffer), i + 1);
4162 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4163                         pe->changed = 1;
4164 #endif
4165                 }
4166         }
4167
4168         return 0;
4169 }
4170
4171 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4172 /*
4173  * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4174  * If the user hits Enter, DFLT is returned.
4175  * Answers like +10 are interpreted as offsets from BASE.
4176  *
4177  * There is no default if DFLT is not between LOW and HIGH.
4178  */
4179 static uint
4180 read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4181 {
4182         uint i;
4183         int default_ok = 1;
4184         static char *ms = NULL;
4185         static int mslen = 0;
4186
4187         if (!ms || strlen(mesg)+100 > mslen) {
4188                 mslen = strlen(mesg)+200;
4189                 ms = xrealloc(ms,mslen);
4190         }
4191
4192         if (dflt < low || dflt > high)
4193                 default_ok = 0;
4194
4195         if (default_ok)
4196                 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
4197                          mesg, low, high, dflt);
4198         else
4199                 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
4200
4201         while (1) {
4202                 int use_default = default_ok;
4203
4204                 /* ask question and read answer */
4205                 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4206                  && *line_ptr != '-' && *line_ptr != '+')
4207                         continue;
4208
4209                 if (*line_ptr == '+' || *line_ptr == '-') {
4210                         int minus = (*line_ptr == '-');
4211                         int absolute = 0;
4212
4213                         i = atoi(line_ptr+1);
4214
4215                         while (isdigit(*++line_ptr))
4216                                 use_default = 0;
4217
4218                         switch (*line_ptr) {
4219                         case 'c':
4220                         case 'C':
4221                                 if (!display_in_cyl_units)
4222                                         i *= heads * sectors;
4223                                 break;
4224                         case 'K':
4225                                 absolute = 1024;
4226                                 break;
4227                         case 'k':
4228                                 absolute = 1000;
4229                                 break;
4230                         case 'm':
4231                         case 'M':
4232                                 absolute = 1000000;
4233                                 break;
4234                         case 'g':
4235                         case 'G':
4236                                 absolute = 1000000000;
4237                                 break;
4238                         default:
4239                                 break;
4240                         }
4241                         if (absolute) {
4242                                 unsigned long long bytes;
4243                                 unsigned long unit;
4244
4245                                 bytes = (unsigned long long) i * absolute;
4246                                 unit = sector_size * units_per_sector;
4247                                 bytes += unit/2; /* round */
4248                                 bytes /= unit;
4249                                 i = bytes;
4250                         }
4251                         if (minus)
4252                                 i = -i;
4253                         i += base;
4254                 } else {
4255                         i = atoi(line_ptr);
4256                         while (isdigit(*line_ptr)) {
4257                                 line_ptr++;
4258                                 use_default = 0;
4259                         }
4260                 }
4261                 if (use_default)
4262                         printf(_("Using default value %u\n"), i = dflt);
4263                 if (i >= low && i <= high)
4264                         break;
4265                 else
4266                         printf(_("Value out of range.\n"));
4267         }
4268         return i;
4269 }
4270
4271 static int
4272 get_partition(int warn, int max)
4273 {
4274         struct pte *pe;
4275         int i;
4276
4277         i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4278         pe = &ptes[i];
4279
4280         if (warn) {
4281                 if (
4282                         (
4283                                 label_sun != current_label_type &&
4284                                 label_sgi != current_label_type &&
4285                                 !pe->part_table->sys_ind
4286                         )
4287 #ifdef CONFIG_FEATURE_SUN_LABEL
4288                         || (
4289                                 label_sun == current_label_type &&
4290                                 (
4291                                         !sunlabel->partitions[i].num_sectors
4292                                         || !sunlabel->infos[i].id
4293                                 )
4294                         )
4295 #endif
4296 #ifdef CONFIG_FEATURE_SGI_LABEL
4297                         || (
4298                                 label_sgi == current_label_type &&
4299                                  !sgi_get_num_sectors(i)
4300                         )
4301 #endif
4302                 ){
4303                         fprintf(stderr,
4304                                 _("Warning: partition %d has empty type\n"),
4305                                 i+1
4306                         );
4307                 }
4308         }
4309         return i;
4310 }
4311
4312 static int
4313 get_existing_partition(int warn, int max)
4314 {
4315         int pno = -1;
4316         int i;
4317
4318         for (i = 0; i < max; i++) {
4319                 struct pte *pe = &ptes[i];
4320                 struct partition *p = pe->part_table;
4321
4322                 if (p && !is_cleared_partition(p)) {
4323                         if (pno >= 0)
4324                                 goto not_unique;
4325                         pno = i;
4326                 }
4327         }
4328         if (pno >= 0) {
4329                 printf(_("Selected partition %d\n"), pno+1);
4330                 return pno;
4331         }
4332         printf(_("No partition is defined yet!\n"));
4333         return -1;
4334
4335  not_unique:
4336         return get_partition(warn, max);
4337 }
4338
4339 static int
4340 get_nonexisting_partition(int warn, int max)
4341 {
4342         int pno = -1;
4343         int i;
4344
4345         for (i = 0; i < max; i++) {
4346                 struct pte *pe = &ptes[i];
4347                 struct partition *p = pe->part_table;
4348
4349                 if (p && is_cleared_partition(p)) {
4350                         if (pno >= 0)
4351                                 goto not_unique;
4352                         pno = i;
4353                 }
4354         }
4355         if (pno >= 0) {
4356                 printf(_("Selected partition %d\n"), pno+1);
4357                 return pno;
4358         }
4359         printf(_("All primary partitions have been defined already!\n"));
4360         return -1;
4361
4362  not_unique:
4363         return get_partition(warn, max);
4364 }
4365
4366
4367 void change_units(void)
4368 {
4369         display_in_cyl_units = !display_in_cyl_units;
4370         update_units();
4371         printf(_("Changing display/entry units to %s\n"),
4372                 str_units(PLURAL));
4373 }
4374
4375 static void
4376 toggle_active(int i)
4377 {
4378         struct pte *pe = &ptes[i];
4379         struct partition *p = pe->part_table;
4380
4381         if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
4382                 fprintf(stderr,
4383                         _("WARNING: Partition %d is an extended partition\n"),
4384                         i + 1);
4385         p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4386         pe->changed = 1;
4387 }
4388
4389 static void
4390 toggle_dos_compatibility_flag(void)
4391 {
4392         dos_compatible_flag = ~dos_compatible_flag;
4393         if (dos_compatible_flag) {
4394                 sector_offset = sectors;
4395                 printf(_("DOS Compatibility flag is set\n"));
4396         }
4397         else {
4398                 sector_offset = 1;
4399                 printf(_("DOS Compatibility flag is not set\n"));
4400         }
4401 }
4402
4403 static void
4404 delete_partition(int i)
4405 {
4406         struct pte *pe = &ptes[i];
4407         struct partition *p = pe->part_table;
4408         struct partition *q = pe->ext_pointer;
4409
4410 /* Note that for the fifth partition (i == 4) we don't actually
4411  * decrement partitions.
4412  */
4413
4414         if (warn_geometry())
4415                 return;         /* C/H/S not set */
4416         pe->changed = 1;
4417
4418 #ifdef CONFIG_FEATURE_SUN_LABEL
4419         if (label_sun == current_label_type) {
4420                 sun_delete_partition(i);
4421                 return;
4422         }
4423 #endif
4424 #ifdef CONFIG_FEATURE_SGI_LABEL
4425         if (label_sgi == current_label_type) {
4426                 sgi_delete_partition(i);
4427                 return;
4428         }
4429 #endif
4430
4431         if (i < 4) {
4432                 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
4433                         partitions = 4;
4434                         ptes[ext_index].ext_pointer = NULL;
4435                         extended_offset = 0;
4436                 }
4437                 clear_partition(p);
4438                 return;
4439         }
4440
4441         if (!q->sys_ind && i > 4) {
4442                 /* the last one in the chain - just delete */
4443                 --partitions;
4444                 --i;
4445                 clear_partition(ptes[i].ext_pointer);
4446                 ptes[i].changed = 1;
4447         } else {
4448                 /* not the last one - further ones will be moved down */
4449                 if (i > 4) {
4450                         /* delete this link in the chain */
4451                         p = ptes[i-1].ext_pointer;
4452                         *p = *q;
4453                         set_start_sect(p, get_start_sect(q));
4454                         set_nr_sects(p, get_nr_sects(q));
4455                         ptes[i-1].changed = 1;
4456                 } else if (partitions > 5) {    /* 5 will be moved to 4 */
4457                         /* the first logical in a longer chain */
4458                         pe = &ptes[5];
4459
4460                         if (pe->part_table) /* prevent SEGFAULT */
4461                                 set_start_sect(pe->part_table,
4462                                                    get_partition_start(pe) -
4463                                                    extended_offset);
4464                         pe->offset = extended_offset;
4465                         pe->changed = 1;
4466                 }
4467
4468                 if (partitions > 5) {
4469                         partitions--;
4470                         while (i < partitions) {
4471                                 ptes[i] = ptes[i+1];
4472                                 i++;
4473                         }
4474                 } else
4475                         /* the only logical: clear only */
4476                         clear_partition(ptes[i].part_table);
4477         }
4478 }
4479
4480 static void
4481 change_sysid(void)
4482 {
4483         int i, sys, origsys;
4484         struct partition *p;
4485
4486 #ifdef CONFIG_FEATURE_SGI_LABEL
4487         /* If sgi_label then don't use get_existing_partition,
4488            let the user select a partition, since get_existing_partition()
4489            only works for Linux like partition tables. */
4490         if (label_sgi != current_label_type) {
4491                 i = get_existing_partition(0, partitions);
4492         } else {
4493                 i = get_partition(0, partitions);
4494         }
4495 #else
4496         i = get_existing_partition(0, partitions);
4497 #endif
4498         if (i == -1)
4499                 return;
4500         p = ptes[i].part_table;
4501         origsys = sys = get_sysid(i);
4502
4503         /* if changing types T to 0 is allowed, then
4504            the reverse change must be allowed, too */
4505         if (!sys && label_sgi != current_label_type &&
4506                 label_sun != current_label_type && !get_nr_sects(p))
4507         {
4508                 printf(_("Partition %d does not exist yet!\n"), i + 1);
4509         } else while (1) {
4510                 sys = read_hex (get_sys_types());
4511
4512                 if (!sys && label_sgi != current_label_type &&
4513                         label_sun != current_label_type)
4514                 {
4515                         printf(_("Type 0 means free space to many systems\n"
4516                                    "(but not to Linux). Having partitions of\n"
4517                                    "type 0 is probably unwise. You can delete\n"
4518                                    "a partition using the `d' command.\n"));
4519                         /* break; */
4520                 }
4521
4522                 if (label_sun != current_label_type && label_sgi != current_label_type) {
4523                         if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
4524                                 printf(_("You cannot change a partition into"
4525                                            " an extended one or vice versa\n"
4526                                            "Delete it first.\n"));
4527                                 break;
4528                         }
4529                 }
4530
4531                 if (sys < 256) {
4532 #ifdef CONFIG_FEATURE_SUN_LABEL
4533                         if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
4534                                 printf(_("Consider leaving partition 3 "
4535                                            "as Whole disk (5),\n"
4536                                            "as SunOS/Solaris expects it and "
4537                                            "even Linux likes it.\n\n"));
4538 #endif
4539 #ifdef CONFIG_FEATURE_SGI_LABEL
4540                         if (label_sgi == current_label_type &&
4541                                 (
4542                                         (i == 10 && sys != ENTIRE_DISK) ||
4543                                         (i == 8 && sys != 0)
4544                                 )
4545                         ){
4546                                 printf(_("Consider leaving partition 9 "
4547                                            "as volume header (0),\nand "
4548                                            "partition 11 as entire volume (6)"
4549                                            "as IRIX expects it.\n\n"));
4550                         }
4551 #endif
4552                         if (sys == origsys)
4553                                 break;
4554 #ifdef CONFIG_FEATURE_SUN_LABEL
4555                         if (label_sun == current_label_type) {
4556                                 sun_change_sysid(i, sys);
4557                         } else
4558 #endif
4559 #ifdef CONFIG_FEATURE_SGI_LABEL
4560                         if (label_sgi == current_label_type) {
4561                                 sgi_change_sysid(i, sys);
4562                         } else
4563 #endif
4564                                 p->sys_ind = sys;
4565
4566                         printf(_("Changed system type of partition %d "
4567                                 "to %x (%s)\n"), i + 1, sys,
4568                                 partition_type(sys));
4569                         ptes[i].changed = 1;
4570                         if (is_dos_partition(origsys) ||
4571                                 is_dos_partition(sys))
4572                                 dos_changed = 1;
4573                         break;
4574                 }
4575         }
4576 }
4577 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4578
4579
4580 /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4581  * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4582  * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4583  * Lubkin Oct.  1991). */
4584
4585 static void
4586 long2chs(ulong ls, uint *c, uint *h, uint *s)
4587 {
4588         int spc = heads * sectors;
4589
4590         *c = ls / spc;
4591         ls = ls % spc;
4592         *h = ls / sectors;
4593         *s = ls % sectors + 1;  /* sectors count from 1 */
4594 }
4595
4596 static void
4597 check_consistency(const struct partition *p, int partition)
4598 {
4599         uint pbc, pbh, pbs;          /* physical beginning c, h, s */
4600         uint pec, peh, pes;          /* physical ending c, h, s */
4601         uint lbc, lbh, lbs;          /* logical beginning c, h, s */
4602         uint lec, leh, les;          /* logical ending c, h, s */
4603
4604         if (!heads || !sectors || (partition >= 4))
4605                 return;         /* do not check extended partitions */
4606
4607 /* physical beginning c, h, s */
4608         pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4609         pbh = p->head;
4610         pbs = p->sector & 0x3f;
4611
4612 /* physical ending c, h, s */
4613         pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4614         peh = p->end_head;
4615         pes = p->end_sector & 0x3f;
4616
4617 /* compute logical beginning (c, h, s) */
4618         long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4619
4620 /* compute logical ending (c, h, s) */
4621         long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4622
4623 /* Same physical / logical beginning? */
4624         if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4625                 printf(_("Partition %d has different physical/logical "
4626                         "beginnings (non-Linux?):\n"), partition + 1);
4627                 printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
4628                 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4629         }
4630
4631 /* Same physical / logical ending? */
4632         if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4633                 printf(_("Partition %d has different physical/logical "
4634                         "endings:\n"), partition + 1);
4635                 printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
4636                 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4637         }
4638
4639 /* Ending on cylinder boundary? */
4640         if (peh != (heads - 1) || pes != sectors) {
4641                 printf(_("Partition %i does not end on cylinder boundary.\n"),
4642                         partition + 1);
4643         }
4644 }
4645
4646 static void
4647 list_disk_geometry(void)
4648 {
4649         long long bytes = (total_number_of_sectors << 9);
4650         long megabytes = bytes/1000000;
4651
4652         if (megabytes < 10000)
4653                 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4654                            disk_device, megabytes, bytes);
4655         else
4656                 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4657                            disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4658         printf(_("%d heads, %d sectors/track, %d cylinders"),
4659                    heads, sectors, cylinders);
4660         if (units_per_sector == 1)
4661                 printf(_(", total %llu sectors"),
4662                            total_number_of_sectors / (sector_size/512));
4663         printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
4664                    str_units(PLURAL),
4665                    units_per_sector, sector_size, units_per_sector * sector_size);
4666 }
4667
4668 /*
4669  * Check whether partition entries are ordered by their starting positions.
4670  * Return 0 if OK. Return i if partition i should have been earlier.
4671  * Two separate checks: primary and logical partitions.
4672  */
4673 static int
4674 wrong_p_order(int *prev)
4675 {
4676         const struct pte *pe;
4677         const struct partition *p;
4678         off_t last_p_start_pos = 0, p_start_pos;
4679         int i, last_i = 0;
4680
4681         for (i = 0 ; i < partitions; i++) {
4682                 if (i == 4) {
4683                         last_i = 4;
4684                         last_p_start_pos = 0;
4685                 }
4686                 pe = &ptes[i];
4687                 if ((p = pe->part_table)->sys_ind) {
4688                         p_start_pos = get_partition_start(pe);
4689
4690                         if (last_p_start_pos > p_start_pos) {
4691                                 if (prev)
4692                                         *prev = last_i;
4693                                 return i;
4694                         }
4695
4696                         last_p_start_pos = p_start_pos;
4697                         last_i = i;
4698                 }
4699         }
4700         return 0;
4701 }
4702
4703 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
4704 /*
4705  * Fix the chain of logicals.
4706  * extended_offset is unchanged, the set of sectors used is unchanged
4707  * The chain is sorted so that sectors increase, and so that
4708  * starting sectors increase.
4709  *
4710  * After this it may still be that cfdisk doesnt like the table.
4711  * (This is because cfdisk considers expanded parts, from link to
4712  * end of partition, and these may still overlap.)
4713  * Now
4714  *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4715  * may help.
4716  */
4717 static void
4718 fix_chain_of_logicals(void)
4719 {
4720         int j, oj, ojj, sj, sjj;
4721         struct partition *pj,*pjj,tmp;
4722
4723         /* Stage 1: sort sectors but leave sector of part 4 */
4724         /* (Its sector is the global extended_offset.) */
4725  stage1:
4726         for (j = 5; j < partitions-1; j++) {
4727                 oj = ptes[j].offset;
4728                 ojj = ptes[j+1].offset;
4729                 if (oj > ojj) {
4730                         ptes[j].offset = ojj;
4731                         ptes[j+1].offset = oj;
4732                         pj = ptes[j].part_table;
4733                         set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4734                         pjj = ptes[j+1].part_table;
4735                         set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4736                         set_start_sect(ptes[j-1].ext_pointer,
4737                                            ojj-extended_offset);
4738                         set_start_sect(ptes[j].ext_pointer,
4739                                            oj-extended_offset);
4740                         goto stage1;
4741                 }
4742         }
4743
4744         /* Stage 2: sort starting sectors */
4745  stage2:
4746         for (j = 4; j < partitions-1; j++) {
4747                 pj = ptes[j].part_table;
4748                 pjj = ptes[j+1].part_table;
4749                 sj = get_start_sect(pj);
4750                 sjj = get_start_sect(pjj);
4751                 oj = ptes[j].offset;
4752                 ojj = ptes[j+1].offset;
4753                 if (oj+sj > ojj+sjj) {
4754                         tmp = *pj;
4755                         *pj = *pjj;
4756                         *pjj = tmp;
4757                         set_start_sect(pj, ojj+sjj-oj);
4758                         set_start_sect(pjj, oj+sj-ojj);
4759                         goto stage2;
4760                 }
4761         }
4762
4763         /* Probably something was changed */
4764         for (j = 4; j < partitions; j++)
4765                 ptes[j].changed = 1;
4766 }
4767
4768
4769 static void
4770 fix_partition_table_order(void)
4771 {
4772         struct pte *pei, *pek;
4773         int i,k;
4774
4775         if (!wrong_p_order(NULL)) {
4776                 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4777                 return;
4778         }
4779
4780         while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4781                 /* partition i should have come earlier, move it */
4782                 /* We have to move data in the MBR */
4783                 struct partition *pi, *pk, *pe, pbuf;
4784                 pei = &ptes[i];
4785                 pek = &ptes[k];
4786
4787                 pe = pei->ext_pointer;
4788                 pei->ext_pointer = pek->ext_pointer;
4789                 pek->ext_pointer = pe;
4790
4791                 pi = pei->part_table;
4792                 pk = pek->part_table;
4793
4794                 memmove(&pbuf, pi, sizeof(struct partition));
4795                 memmove(pi, pk, sizeof(struct partition));
4796                 memmove(pk, &pbuf, sizeof(struct partition));
4797
4798                 pei->changed = pek->changed = 1;
4799         }
4800
4801         if (i)
4802                 fix_chain_of_logicals();
4803
4804         printf("Done.\n");
4805
4806 }
4807 #endif
4808
4809 static void
4810 list_table(int xtra)
4811 {
4812         const struct partition *p;
4813         int i, w;
4814
4815 #ifdef CONFIG_FEATURE_SUN_LABEL
4816         if (label_sun == current_label_type) {
4817                 sun_list_table(xtra);
4818                 return;
4819         }
4820 #endif
4821
4822 #ifdef CONFIG_FEATURE_SGI_LABEL
4823         if (label_sgi == current_label_type) {
4824                 sgi_list_table(xtra);
4825                 return;
4826         }
4827 #endif
4828
4829         list_disk_geometry();
4830
4831 #ifdef CONFIG_FEATURE_OSF_LABEL
4832         if (label_osf == current_label_type) {
4833                 xbsd_print_disklabel(xtra);
4834                 return;
4835         }
4836 #endif
4837
4838         /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4839            but if the device name ends in a digit, say /dev/foo1,
4840            then the partition is called /dev/foo1p3. */
4841         w = strlen(disk_device);
4842         if (w && isdigit(disk_device[w-1]))
4843                 w++;
4844         if (w < 5)
4845                 w = 5;
4846
4847         printf(_("%*s Boot    Start       End    Blocks   Id  System\n"),
4848                    w+1, _("Device"));
4849
4850         for (i = 0; i < partitions; i++) {
4851                 const struct pte *pe = &ptes[i];
4852
4853                 p = pe->part_table;
4854                 if (p && !is_cleared_partition(p)) {
4855                         off_t psects = get_nr_sects(p);
4856                         off_t pblocks = psects;
4857                         unsigned int podd = 0;
4858
4859                         if (sector_size < 1024) {
4860                                 pblocks /= (1024 / sector_size);
4861                                 podd = psects % (1024 / sector_size);
4862                         }
4863                         if (sector_size > 1024)
4864                                 pblocks *= (sector_size / 1024);
4865                         printf(
4866                                 "%s  %c %11llu %11llu %11llu%c  %2x  %s\n",
4867                         partname(disk_device, i+1, w+2),
4868 /* boot flag */         !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4869                         ? '*' : '?',
4870 /* start */             (unsigned long long) cround(get_partition_start(pe)),
4871 /* end */               (unsigned long long) cround(get_partition_start(pe) + psects
4872                                 - (psects ? 1 : 0)),
4873 /* odd flag on end */   (unsigned long long) pblocks, podd ? '+' : ' ',
4874 /* type id */           p->sys_ind,
4875 /* type name */         partition_type(p->sys_ind));
4876                         check_consistency(p, i);
4877                 }
4878         }
4879
4880         /* Is partition table in disk order? It need not be, but... */
4881         /* partition table entries are not checked for correct order if this
4882            is a sgi, sun or aix labeled disk... */
4883         if (label_dos == current_label_type && wrong_p_order(NULL)) {
4884                 /* FIXME */
4885                 printf(_("\nPartition table entries are not in disk order\n"));
4886         }
4887 }
4888
4889 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
4890 static void
4891 x_list_table(int extend)
4892 {
4893         const struct pte *pe;
4894         const struct partition *p;
4895         int i;
4896
4897         printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4898                 disk_device, heads, sectors, cylinders);
4899         printf(_("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl    Start     Size ID\n"));
4900         for (i = 0 ; i < partitions; i++) {
4901                 pe = &ptes[i];
4902                 p = (extend ? pe->ext_pointer : pe->part_table);
4903                 if (p != NULL) {
4904                         printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
4905                                 i + 1, p->boot_ind, p->head,
4906                                 sector(p->sector),
4907                                 cylinder(p->sector, p->cyl), p->end_head,
4908                                 sector(p->end_sector),
4909                                 cylinder(p->end_sector, p->end_cyl),
4910                                 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4911                         if (p->sys_ind)
4912                                 check_consistency(p, i);
4913                 }
4914         }
4915 }
4916 #endif
4917
4918 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4919 static void
4920 fill_bounds(off_t *first, off_t *last)
4921 {
4922         int i;
4923         const struct pte *pe = &ptes[0];
4924         const struct partition *p;
4925
4926         for (i = 0; i < partitions; pe++,i++) {
4927                 p = pe->part_table;
4928                 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
4929                         first[i] = 0xffffffff;
4930                         last[i] = 0;
4931                 } else {
4932                         first[i] = get_partition_start(pe);
4933                         last[i] = first[i] + get_nr_sects(p) - 1;
4934                 }
4935         }
4936 }
4937
4938 static void
4939 check(int n, uint h, uint s, uint c, off_t start)
4940 {
4941         off_t total, real_s, real_c;
4942
4943         real_s = sector(s) - 1;
4944         real_c = cylinder(s, c);
4945         total = (real_c * sectors + real_s) * heads + h;
4946         if (!total)
4947                 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4948         if (h >= heads)
4949                 fprintf(stderr,
4950                         _("Partition %d: head %d greater than maximum %d\n"),
4951                         n, h + 1, heads);
4952         if (real_s >= sectors)
4953                 fprintf(stderr, _("Partition %d: sector %d greater than "
4954                         "maximum %d\n"), n, s, sectors);
4955         if (real_c >= cylinders)
4956                 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4957                         "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
4958         if (cylinders <= 1024 && start != total)
4959                 fprintf(stderr,
4960                         _("Partition %d: previous sectors %llu disagrees with "
4961                         "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
4962 }
4963
4964 static void
4965 verify(void)
4966 {
4967         int i, j;
4968         uint total = 1;
4969         off_t first[partitions], last[partitions];
4970         struct partition *p;
4971
4972         if (warn_geometry())
4973                 return;
4974
4975 #ifdef CONFIG_FEATURE_SUN_LABEL
4976         if (label_sun == current_label_type) {
4977                 verify_sun();
4978                 return;
4979         }
4980 #endif
4981 #ifdef CONFIG_FEATURE_SGI_LABEL
4982         if (label_sgi == current_label_type) {
4983                 verify_sgi(1);
4984                 return;
4985         }
4986 #endif
4987
4988         fill_bounds(first, last);
4989         for (i = 0; i < partitions; i++) {
4990                 struct pte *pe = &ptes[i];
4991
4992                 p = pe->part_table;
4993                 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
4994                         check_consistency(p, i);
4995                         if (get_partition_start(pe) < first[i])
4996                                 printf(_("Warning: bad start-of-data in "
4997                                         "partition %d\n"), i + 1);
4998                         check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4999                                 last[i]);
5000                         total += last[i] + 1 - first[i];
5001                         for (j = 0; j < i; j++)
5002                         if ((first[i] >= first[j] && first[i] <= last[j])
5003                          || ((last[i] <= last[j] && last[i] >= first[j]))) {
5004                                 printf(_("Warning: partition %d overlaps "
5005                                         "partition %d.\n"), j + 1, i + 1);
5006                                 total += first[i] >= first[j] ?
5007                                         first[i] : first[j];
5008                                 total -= last[i] <= last[j] ?
5009                                         last[i] : last[j];
5010                         }
5011                 }
5012         }
5013
5014         if (extended_offset) {
5015                 struct pte *pex = &ptes[ext_index];
5016                 off_t e_last = get_start_sect(pex->part_table) +
5017                         get_nr_sects(pex->part_table) - 1;
5018
5019                 for (i = 4; i < partitions; i++) {
5020                         total++;
5021                         p = ptes[i].part_table;
5022                         if (!p->sys_ind) {
5023                                 if (i != 4 || i + 1 < partitions)
5024                                         printf(_("Warning: partition %d "
5025                                                 "is empty\n"), i + 1);
5026                         }
5027                         else if (first[i] < extended_offset ||
5028                                         last[i] > e_last)
5029                                 printf(_("Logical partition %d not entirely in "
5030                                         "partition %d\n"), i + 1, ext_index + 1);
5031                 }
5032         }
5033
5034         if (total > heads * sectors * cylinders)
5035                 printf(_("Total allocated sectors %d greater than the maximum "
5036                         "%d\n"), total, heads * sectors * cylinders);
5037         else if ((total = heads * sectors * cylinders - total) != 0)
5038                 printf(_("%d unallocated sectors\n"), total);
5039 }
5040
5041 static void
5042 add_partition(int n, int sys)
5043 {
5044         char mesg[256];         /* 48 does not suffice in Japanese */
5045         int i, num_read = 0;
5046         struct partition *p = ptes[n].part_table;
5047         struct partition *q = ptes[ext_index].part_table;
5048         long long llimit;
5049         off_t start, stop = 0, limit, temp,
5050                 first[partitions], last[partitions];
5051
5052         if (p && p->sys_ind) {
5053                 printf(_("Partition %d is already defined.  Delete "
5054                          "it before re-adding it.\n"), n + 1);
5055                 return;
5056         }
5057         fill_bounds(first, last);
5058         if (n < 4) {
5059                 start = sector_offset;
5060                 if (display_in_cyl_units || !total_number_of_sectors)
5061                         llimit = heads * sectors * cylinders - 1;
5062                 else
5063                         llimit = total_number_of_sectors - 1;
5064                 limit = llimit;
5065                 if (limit != llimit)
5066                         limit = 0x7fffffff;
5067                 if (extended_offset) {
5068                         first[ext_index] = extended_offset;
5069                         last[ext_index] = get_start_sect(q) +
5070                                 get_nr_sects(q) - 1;
5071                 }
5072         } else {
5073                 start = extended_offset + sector_offset;
5074                 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5075         }
5076         if (display_in_cyl_units)
5077                 for (i = 0; i < partitions; i++)
5078                         first[i] = (cround(first[i]) - 1) * units_per_sector;
5079
5080         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5081         do {
5082                 temp = start;
5083                 for (i = 0; i < partitions; i++) {
5084                         int lastplusoff;
5085
5086                         if (start == ptes[i].offset)
5087                                 start += sector_offset;
5088                         lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
5089                         if (start >= first[i] && start <= lastplusoff)
5090                                 start = lastplusoff + 1;
5091                 }
5092                 if (start > limit)
5093                         break;
5094                 if (start >= temp+units_per_sector && num_read) {
5095                         printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
5096                         temp = start;
5097                         num_read = 0;
5098                 }
5099                 if (!num_read && start == temp) {
5100                         off_t saved_start;
5101
5102                         saved_start = start;
5103                         start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5104                                          0, mesg);
5105                         if (display_in_cyl_units) {
5106                                 start = (start - 1) * units_per_sector;
5107                                 if (start < saved_start) start = saved_start;
5108                         }
5109                         num_read = 1;
5110                 }
5111         } while (start != temp || !num_read);
5112         if (n > 4) {                    /* NOT for fifth partition */
5113                 struct pte *pe = &ptes[n];
5114
5115                 pe->offset = start - sector_offset;
5116                 if (pe->offset == extended_offset) { /* must be corrected */
5117                         pe->offset++;
5118                         if (sector_offset == 1)
5119                                 start++;
5120                 }
5121         }
5122
5123         for (i = 0; i < partitions; i++) {
5124                 struct pte *pe = &ptes[i];
5125
5126                 if (start < pe->offset && limit >= pe->offset)
5127                         limit = pe->offset - 1;
5128                 if (start < first[i] && limit >= first[i])
5129                         limit = first[i] - 1;
5130         }
5131         if (start > limit) {
5132                 printf(_("No free sectors available\n"));
5133                 if (n > 4)
5134                         partitions--;
5135                 return;
5136         }
5137         if (cround(start) == cround(limit)) {
5138                 stop = limit;
5139         } else {
5140                 snprintf(mesg, sizeof(mesg),
5141                          _("Last %s or +size or +sizeM or +sizeK"),
5142                          str_units(SINGULAR));
5143                 stop = read_int(cround(start), cround(limit), cround(limit),
5144                                 cround(start), mesg);
5145                 if (display_in_cyl_units) {
5146                         stop = stop * units_per_sector - 1;
5147                         if (stop >limit)
5148                                 stop = limit;
5149                 }
5150         }
5151
5152         set_partition(n, 0, start, stop, sys);
5153         if (n > 4)
5154                 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5155
5156         if (IS_EXTENDED(sys)) {
5157                 struct pte *pe4 = &ptes[4];
5158                 struct pte *pen = &ptes[n];
5159
5160                 ext_index = n;
5161                 pen->ext_pointer = p;
5162                 pe4->offset = extended_offset = start;
5163                 pe4->sectorbuffer = xzalloc(sector_size);
5164                 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5165                 pe4->ext_pointer = pe4->part_table + 1;
5166                 pe4->changed = 1;
5167                 partitions = 5;
5168         }
5169 }
5170
5171 static void
5172 add_logical(void)
5173 {
5174         if (partitions > 5 || ptes[4].part_table->sys_ind) {
5175                 struct pte *pe = &ptes[partitions];
5176
5177                 pe->sectorbuffer = xzalloc(sector_size);
5178                 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5179                 pe->ext_pointer = pe->part_table + 1;
5180                 pe->offset = 0;
5181                 pe->changed = 1;
5182                 partitions++;
5183         }
5184         add_partition(partitions - 1, LINUX_NATIVE);
5185 }
5186
5187 static void
5188 new_partition(void)
5189 {
5190         int i, free_primary = 0;
5191
5192         if (warn_geometry())
5193                 return;
5194
5195 #ifdef CONFIG_FEATURE_SUN_LABEL
5196         if (label_sun == current_label_type) {
5197                 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5198                 return;
5199         }
5200 #endif
5201 #ifdef CONFIG_FEATURE_SGI_LABEL
5202         if (label_sgi == current_label_type) {
5203                 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5204                 return;
5205         }
5206 #endif
5207 #ifdef CONFIG_FEATURE_AIX_LABEL
5208         if (label_aix == current_label_type) {
5209                 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5210                          "\n\tIf you want to add DOS-type partitions, create"
5211                          "\n\ta new empty DOS partition table first. (Use o.)"
5212                          "\n\tWARNING: "
5213                          "This will destroy the present disk contents.\n"));
5214                 return;
5215         }
5216 #endif
5217
5218         for (i = 0; i < 4; i++)
5219                 free_primary += !ptes[i].part_table->sys_ind;
5220
5221         if (!free_primary && partitions >= MAXIMUM_PARTS) {
5222                 printf(_("The maximum number of partitions has been created\n"));
5223                 return;
5224         }
5225
5226         if (!free_primary) {
5227                 if (extended_offset)
5228                         add_logical();
5229                 else
5230                         printf(_("You must delete some partition and add "
5231                                  "an extended partition first\n"));
5232         } else {
5233                 char c, line[LINE_LENGTH];
5234                 snprintf(line, sizeof(line), "%s\n   %s\n   p   primary "
5235                                                 "partition (1-4)\n",
5236                          "Command action", (extended_offset ?
5237                          "l   logical (5 or over)" : "e   extended"));
5238                 while (1) {
5239                         if ((c = read_char(line)) == 'p' || c == 'P') {
5240                                 i = get_nonexisting_partition(0, 4);
5241                                 if (i >= 0)
5242                                         add_partition(i, LINUX_NATIVE);
5243                                 return;
5244                         }
5245                         else if (c == 'l' && extended_offset) {
5246                                 add_logical();
5247                                 return;
5248                         }
5249                         else if (c == 'e' && !extended_offset) {
5250                                 i = get_nonexisting_partition(0, 4);
5251                                 if (i >= 0)
5252                                         add_partition(i, EXTENDED);
5253                                 return;
5254                         }
5255                         else
5256                                 printf(_("Invalid partition number "
5257                                          "for type `%c'\n"), c);
5258                 }
5259         }
5260 }
5261
5262 static void
5263 write_table(void)
5264 {
5265         int i;
5266
5267         if (label_dos == current_label_type) {
5268                 for (i = 0; i < 3; i++)
5269                         if (ptes[i].changed)
5270                                 ptes[3].changed = 1;
5271                 for (i = 3; i < partitions; i++) {
5272                         struct pte *pe = &ptes[i];
5273
5274                         if (pe->changed) {
5275                                 write_part_table_flag(pe->sectorbuffer);
5276                                 write_sector(pe->offset, pe->sectorbuffer);
5277                         }
5278                 }
5279         }
5280 #ifdef CONFIG_FEATURE_SGI_LABEL
5281         else if (label_sgi == current_label_type) {
5282                 /* no test on change? the printf below might be mistaken */
5283                 sgi_write_table();
5284         }
5285 #endif
5286 #ifdef CONFIG_FEATURE_SUN_LABEL
5287         else if (label_sun == current_label_type) {
5288                 int needw = 0;
5289
5290                 for (i = 0; i < 8; i++)
5291                         if (ptes[i].changed)
5292                                 needw = 1;
5293                 if (needw)
5294                         sun_write_table();
5295         }
5296 #endif
5297
5298         printf(_("The partition table has been altered!\n\n"));
5299         reread_partition_table(1);
5300 }
5301
5302 static void
5303 reread_partition_table(int leave)
5304 {
5305         int error = 0;
5306         int i;
5307
5308         printf(_("Calling ioctl() to re-read partition table.\n"));
5309         sync();
5310         sleep(2);
5311         if ((i = ioctl(fd, BLKRRPART)) != 0) {
5312                 error = errno;
5313         } else {
5314                 /* some kernel versions (1.2.x) seem to have trouble
5315                    rereading the partition table, but if asked to do it
5316                    twice, the second time works. - biro@yggdrasil.com */
5317                 sync();
5318                 sleep(2);
5319                 if ((i = ioctl(fd, BLKRRPART)) != 0)
5320                         error = errno;
5321         }
5322
5323         if (i) {
5324                 printf(_("\nWARNING: Re-reading the partition table "
5325                          "failed with error %d: %s.\n"
5326                          "The kernel still uses the old table.\n"
5327                          "The new table will be used "
5328                          "at the next reboot.\n"),
5329                         error, strerror(error));
5330         }
5331
5332         if (dos_changed)
5333                 printf(
5334                 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5335                 "partitions, please see the fdisk manual page for additional\n"
5336                 "information.\n"));
5337
5338         if (leave) {
5339                 close(fd);
5340
5341                 printf(_("Syncing disks.\n"));
5342                 sync();
5343                 sleep(4);               /* for sync() */
5344                 exit(!!i);
5345         }
5346 }
5347 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
5348
5349 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
5350 #define MAX_PER_LINE    16
5351 static void
5352 print_buffer(char *pbuffer)
5353 {
5354         int i,l;
5355
5356         for (i = 0, l = 0; i < sector_size; i++, l++) {
5357                 if (l == 0)
5358                         printf("0x%03X:", i);
5359                 printf(" %02X", (unsigned char) pbuffer[i]);
5360                 if (l == MAX_PER_LINE - 1) {
5361                         printf("\n");
5362                         l = -1;
5363                 }
5364         }
5365         if (l > 0)
5366                 printf("\n");
5367         printf("\n");
5368 }
5369
5370
5371 static void
5372 print_raw(void)
5373 {
5374         int i;
5375
5376         printf(_("Device: %s\n"), disk_device);
5377 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5378         if (label_sun == current_label_type || label_sgi == current_label_type)
5379                 print_buffer(MBRbuffer);
5380         else
5381 #endif
5382                 for (i = 3; i < partitions; i++)
5383                         print_buffer(ptes[i].sectorbuffer);
5384 }
5385
5386 static void
5387 move_begin(int i)
5388 {
5389         struct pte *pe = &ptes[i];
5390         struct partition *p = pe->part_table;
5391         off_t new, first;
5392
5393         if (warn_geometry())
5394                 return;
5395         if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
5396                 printf(_("Partition %d has no data area\n"), i + 1);
5397                 return;
5398         }
5399         first = get_partition_start(pe);
5400         new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5401                            _("New beginning of data")) - pe->offset;
5402
5403         if (new != get_nr_sects(p)) {
5404                 first = get_nr_sects(p) + get_start_sect(p) - new;
5405                 set_nr_sects(p, first);
5406                 set_start_sect(p, new);
5407                 pe->changed = 1;
5408         }
5409 }
5410
5411 static void
5412 xselect(void)
5413 {
5414         char c;
5415
5416         while (1) {
5417                 putchar('\n');
5418                 c = tolower(read_char(_("Expert command (m for help): ")));
5419                 switch (c) {
5420                 case 'a':
5421 #ifdef CONFIG_FEATURE_SUN_LABEL
5422                         if (label_sun == current_label_type)
5423                                 sun_set_alt_cyl();
5424 #endif
5425                         break;
5426                 case 'b':
5427                         if (label_dos == current_label_type)
5428                                 move_begin(get_partition(0, partitions));
5429                         break;
5430                 case 'c':
5431                         user_cylinders = cylinders =
5432                                 read_int(1, cylinders, 1048576, 0,
5433                                         _("Number of cylinders"));
5434 #ifdef CONFIG_FEATURE_SUN_LABEL
5435                         if (label_sun == current_label_type)
5436                                 sun_set_ncyl(cylinders);
5437 #endif
5438                         if (label_dos == current_label_type)
5439                                 warn_cylinders();
5440                         break;
5441                 case 'd':
5442                         print_raw();
5443                         break;
5444                 case 'e':
5445 #ifdef CONFIG_FEATURE_SGI_LABEL
5446                         if (label_sgi == current_label_type)
5447                                 sgi_set_xcyl();
5448                         else
5449 #endif
5450 #ifdef CONFIG_FEATURE_SUN_LABEL
5451                          if (label_sun == current_label_type)
5452                                 sun_set_xcyl();
5453                          else
5454 #endif
5455                         if (label_dos == current_label_type)
5456                                 x_list_table(1);
5457                         break;
5458                 case 'f':
5459                         if (label_dos == current_label_type)
5460                                 fix_partition_table_order();
5461                         break;
5462                 case 'g':
5463 #ifdef CONFIG_FEATURE_SGI_LABEL
5464                         create_sgilabel();
5465 #endif
5466                         break;
5467                 case 'h':
5468                         user_heads = heads = read_int(1, heads, 256, 0,
5469                                         _("Number of heads"));
5470                         update_units();
5471                         break;
5472                 case 'i':
5473 #ifdef CONFIG_FEATURE_SUN_LABEL
5474                         if (label_sun == current_label_type)
5475                                 sun_set_ilfact();
5476 #endif
5477                         break;
5478                 case 'o':
5479 #ifdef CONFIG_FEATURE_SUN_LABEL
5480                         if (label_sun == current_label_type)
5481                                 sun_set_rspeed();
5482 #endif
5483                         break;
5484                 case 'p':
5485 #ifdef CONFIG_FEATURE_SUN_LABEL
5486                         if (label_sun == current_label_type)
5487                                 list_table(1);
5488                         else
5489 #endif
5490                                 x_list_table(0);
5491                         break;
5492                 case 'q':
5493                         close(fd);
5494                         printf("\n");
5495                         exit(0);
5496                 case 'r':
5497                         return;
5498                 case 's':
5499                         user_sectors = sectors = read_int(1, sectors, 63, 0,
5500                                            _("Number of sectors"));
5501                         if (dos_compatible_flag) {
5502                                 sector_offset = sectors;
5503                                 fprintf(stderr, _("Warning: setting "
5504                                         "sector offset for DOS "
5505                                         "compatiblity\n"));
5506                         }
5507                         update_units();
5508                         break;
5509                 case 'v':
5510                         verify();
5511                         break;
5512                 case 'w':
5513                         write_table();  /* does not return */
5514                         break;
5515                 case 'y':
5516 #ifdef CONFIG_FEATURE_SUN_LABEL
5517                         if (label_sun == current_label_type)
5518                                 sun_set_pcylcount();
5519 #endif
5520                         break;
5521                 default:
5522                         xmenu();
5523                 }
5524         }
5525 }
5526 #endif /* ADVANCED mode */
5527
5528 static int
5529 is_ide_cdrom_or_tape(const char *device)
5530 {
5531         FILE *procf;
5532         char buf[100];
5533         struct stat statbuf;
5534         int is_ide = 0;
5535
5536         /* No device was given explicitly, and we are trying some
5537            likely things.  But opening /dev/hdc may produce errors like
5538            "hdc: tray open or drive not ready"
5539            if it happens to be a CD-ROM drive. It even happens that
5540            the process hangs on the attempt to read a music CD.
5541            So try to be careful. This only works since 2.1.73. */
5542
5543         if (strncmp("/dev/hd", device, 7))
5544                 return 0;
5545
5546         snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5547         procf = fopen(buf, "r");
5548         if (procf != NULL && fgets(buf, sizeof(buf), procf))
5549                 is_ide = (!strncmp(buf, "cdrom", 5) ||
5550                           !strncmp(buf, "tape", 4));
5551         else
5552                 /* Now when this proc file does not exist, skip the
5553                    device when it is read-only. */
5554                 if (stat(device, &statbuf) == 0)
5555                         is_ide = ((statbuf.st_mode & 0222) == 0);
5556
5557         if (procf)
5558                 fclose(procf);
5559         return is_ide;
5560 }
5561
5562
5563 static void
5564 try(const char *device, int user_specified)
5565 {
5566         int gb;
5567
5568         disk_device = device;
5569         if (setjmp(listingbuf))
5570                 return;
5571         if (!user_specified)
5572                 if (is_ide_cdrom_or_tape(device))
5573                         return;
5574         if ((fd = open(disk_device, type_open)) >= 0) {
5575                 gb = get_boot(try_only);
5576                 if (gb > 0) {   /* I/O error */
5577                         close(fd);
5578                 } else if (gb < 0) { /* no DOS signature */
5579                         list_disk_geometry();
5580                         if (label_aix == current_label_type){
5581                                 return;
5582                         }
5583 #ifdef CONFIG_FEATURE_OSF_LABEL
5584                         if (btrydev(device) < 0)
5585 #endif
5586                                 fprintf(stderr,
5587                                         _("Disk %s doesn't contain a valid "
5588                                         "partition table\n"), device);
5589                         close(fd);
5590                 } else {
5591                         close(fd);
5592                         list_table(0);
5593 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5594                         if (label_sun != current_label_type && partitions > 4){
5595                                 delete_partition(ext_index);
5596                         }
5597 #endif
5598                 }
5599         } else {
5600                 /* Ignore other errors, since we try IDE
5601                    and SCSI hard disks which may not be
5602                    installed on the system. */
5603                 if (errno == EACCES) {
5604                         fprintf(stderr, _("Cannot open %s\n"), device);
5605                         return;
5606                 }
5607         }
5608 }
5609
5610 /* for fdisk -l: try all things in /proc/partitions
5611    that look like a partition name (do not end in a digit) */
5612 static void
5613 tryprocpt(void)
5614 {
5615         FILE *procpt;
5616         char line[100], ptname[100], devname[120], *s;
5617         int ma, mi, sz;
5618
5619         procpt = bb_wfopen(PROC_PARTITIONS, "r");
5620
5621         while (fgets(line, sizeof(line), procpt)) {
5622                 if (sscanf(line, " %d %d %d %[^\n ]",
5623                                 &ma, &mi, &sz, ptname) != 4)
5624                         continue;
5625                 for (s = ptname; *s; s++);
5626                 if (isdigit(s[-1]))
5627                         continue;
5628                 sprintf(devname, "/dev/%s", ptname);
5629                 try(devname, 0);
5630         }
5631 #ifdef CONFIG_FEATURE_CLEAN_UP
5632         fclose(procpt);
5633 #endif
5634 }
5635
5636 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5637 static void
5638 unknown_command(int c)
5639 {
5640         printf(_("%c: unknown command\n"), c);
5641 }
5642 #endif
5643
5644 int fdisk_main(int argc, char **argv)
5645 {
5646         int c;
5647 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5648         int optl = 0;
5649 #endif
5650 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5651         int opts = 0;
5652 #endif
5653         /*
5654          * Calls:
5655          *  fdisk -v
5656          *  fdisk -l [-b sectorsize] [-u] device ...
5657          *  fdisk -s [partition] ...
5658          *  fdisk [-b sectorsize] [-u] device
5659          *
5660          * Options -C, -H, -S set the geometry.
5661          *
5662          */
5663         while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5664 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5665                                         "s"
5666 #endif
5667                                                 )) != -1) {
5668                 switch (c) {
5669                 case 'b':
5670                         /* Ugly: this sector size is really per device,
5671                            so cannot be combined with multiple disks,
5672                            and te same goes for the C/H/S options.
5673                         */
5674                         sector_size = atoi(optarg);
5675                         if (sector_size != 512 && sector_size != 1024 &&
5676                                 sector_size != 2048)
5677                                 bb_show_usage();
5678                         sector_offset = 2;
5679                         user_set_sector_size = 1;
5680                         break;
5681                 case 'C':
5682                         user_cylinders = atoi(optarg);
5683                         break;
5684                 case 'H':
5685                         user_heads = atoi(optarg);
5686                         if (user_heads <= 0 || user_heads >= 256)
5687                                 user_heads = 0;
5688                         break;
5689                 case 'S':
5690                         user_sectors = atoi(optarg);
5691                         if (user_sectors <= 0 || user_sectors >= 64)
5692                                 user_sectors = 0;
5693                         break;
5694                 case 'l':
5695 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5696                         optl = 1;
5697 #endif
5698                         break;
5699 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5700                 case 's':
5701                         opts = 1;
5702                         break;
5703 #endif
5704                 case 'u':
5705                         display_in_cyl_units = 0;
5706                         break;
5707                 case 'V':
5708                 case 'v':
5709                         printf("fdisk v" UTIL_LINUX_VERSION "\n");
5710                         return 0;
5711                 default:
5712                         bb_show_usage();
5713                 }
5714         }
5715
5716         if (user_set_sector_size && argc-optind != 1)
5717                 printf(_("Warning: the -b (set sector size) option should"
5718                          " be used with one specified device\n"));
5719
5720 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5721         if (optl) {
5722                 nowarn = 1;
5723 #endif
5724                 type_open = O_RDONLY;
5725                 if (argc > optind) {
5726                         int k;
5727 #if __GNUC__
5728                         /* avoid gcc warning:
5729                            variable `k' might be clobbered by `longjmp' */
5730                         (void)&k;
5731 #endif
5732                         listing = 1;
5733                         for (k = optind; k < argc; k++)
5734                                 try(argv[k], 1);
5735                 } else {
5736                         /* we no longer have default device names */
5737                         /* but, we can use /proc/partitions instead */
5738                         tryprocpt();
5739                 }
5740                 return 0;
5741 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5742         }
5743 #endif
5744
5745 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5746         if (opts) {
5747                 long size;
5748                 int j;
5749
5750                 nowarn = 1;
5751                 type_open = O_RDONLY;
5752
5753                 opts = argc - optind;
5754                 if (opts <= 0)
5755                         bb_show_usage();
5756
5757                 for (j = optind; j < argc; j++) {
5758                         disk_device = argv[j];
5759                         if ((fd = open(disk_device, type_open)) < 0)
5760                                 fdisk_fatal(unable_to_open);
5761                         if (ioctl(fd, BLKGETSIZE, &size))
5762                                 fdisk_fatal(ioctl_error);
5763                         close(fd);
5764                         if (opts == 1)
5765                                 printf("%ld\n", size/2);
5766                         else
5767                                 printf("%s: %ld\n", argv[j], size/2);
5768                 }
5769                 return 0;
5770         }
5771 #endif
5772
5773 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5774         if (argc-optind == 1)
5775                 disk_device = argv[optind];
5776         else
5777                 bb_show_usage();
5778
5779         get_boot(fdisk);
5780
5781 #ifdef CONFIG_FEATURE_OSF_LABEL
5782         if (label_osf == current_label_type) {
5783                 /* OSF label, and no DOS label */
5784                 printf(_("Detected an OSF/1 disklabel on %s, entering "
5785                          "disklabel mode.\n"),
5786                            disk_device);
5787                 bselect();
5788                 /*Why do we do this?  It seems to be counter-intuitive*/
5789                 current_label_type = label_dos;
5790                 /* If we return we may want to make an empty DOS label? */
5791         }
5792 #endif
5793
5794         while (1) {
5795                 putchar('\n');
5796                 c = tolower(read_char(_("Command (m for help): ")));
5797                 switch (c) {
5798                 case 'a':
5799                         if (label_dos == current_label_type)
5800                                 toggle_active(get_partition(1, partitions));
5801 #ifdef CONFIG_FEATURE_SUN_LABEL
5802                         else if (label_sun == current_label_type)
5803                                 toggle_sunflags(get_partition(1, partitions),
5804                                                 0x01);
5805 #endif
5806 #ifdef CONFIG_FEATURE_SGI_LABEL
5807                         else if (label_sgi == current_label_type)
5808                                 sgi_set_bootpartition(
5809                                         get_partition(1, partitions));
5810 #endif
5811                         else
5812                                 unknown_command(c);
5813                         break;
5814                 case 'b':
5815 #ifdef CONFIG_FEATURE_SGI_LABEL
5816                         if (label_sgi == current_label_type) {
5817                                 printf(_("\nThe current boot file is: %s\n"),
5818                                         sgi_get_bootfile());
5819                                 if (read_chars(_("Please enter the name of the "
5820                                                    "new boot file: ")) == '\n')
5821                                         printf(_("Boot file unchanged\n"));
5822                                 else
5823                                         sgi_set_bootfile(line_ptr);
5824                         } else
5825 #endif
5826 #ifdef CONFIG_FEATURE_OSF_LABEL
5827                                 bselect();
5828 #endif
5829                         break;
5830                 case 'c':
5831                         if (label_dos == current_label_type)
5832                                 toggle_dos_compatibility_flag();
5833 #ifdef CONFIG_FEATURE_SUN_LABEL
5834                         else if (label_sun == current_label_type)
5835                                 toggle_sunflags(get_partition(1, partitions),
5836                                                 0x10);
5837 #endif
5838 #ifdef CONFIG_FEATURE_SGI_LABEL
5839                         else if (label_sgi == current_label_type)
5840                                 sgi_set_swappartition(
5841                                                 get_partition(1, partitions));
5842 #endif
5843                         else
5844                                 unknown_command(c);
5845                         break;
5846                 case 'd':
5847                         {
5848                                 int j;
5849 #ifdef CONFIG_FEATURE_SGI_LABEL
5850                         /* If sgi_label then don't use get_existing_partition,
5851                            let the user select a partition, since
5852                            get_existing_partition() only works for Linux-like
5853                            partition tables */
5854                                 if (label_sgi != current_label_type) {
5855                                         j = get_existing_partition(1, partitions);
5856                                 } else {
5857                                         j = get_partition(1, partitions);
5858                                 }
5859 #else
5860                                 j = get_existing_partition(1, partitions);
5861 #endif
5862                                 if (j >= 0)
5863                                         delete_partition(j);
5864                         }
5865                         break;
5866                 case 'i':
5867 #ifdef CONFIG_FEATURE_SGI_LABEL
5868                         if (label_sgi == current_label_type)
5869                                 create_sgiinfo();
5870                         else
5871 #endif
5872                                 unknown_command(c);
5873                 case 'l':
5874                         list_types(get_sys_types());
5875                         break;
5876                 case 'm':
5877                         menu();
5878                         break;
5879                 case 'n':
5880                         new_partition();
5881                         break;
5882                 case 'o':
5883                         create_doslabel();
5884                         break;
5885                 case 'p':
5886                         list_table(0);
5887                         break;
5888                 case 'q':
5889                         close(fd);
5890                         printf("\n");
5891                         return 0;
5892                 case 's':
5893 #ifdef CONFIG_FEATURE_SUN_LABEL
5894                         create_sunlabel();
5895 #endif
5896                         break;
5897                 case 't':
5898                         change_sysid();
5899                         break;
5900                 case 'u':
5901                         change_units();
5902                         break;
5903                 case 'v':
5904                         verify();
5905                         break;
5906                 case 'w':
5907                         write_table();          /* does not return */
5908                         break;
5909 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
5910                 case 'x':
5911 #ifdef CONFIG_FEATURE_SGI_LABEL
5912                         if (label_sgi == current_label_type) {
5913                                 fprintf(stderr,
5914                                         _("\n\tSorry, no experts menu for SGI "
5915                                         "partition tables available.\n\n"));
5916                         } else
5917 #endif
5918
5919                                 xselect();
5920                         break;
5921 #endif
5922                 default:
5923                         unknown_command(c);
5924                         menu();
5925                 }
5926         }
5927         return 0;
5928 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
5929 }