attempt to regularize atoi mess.
[oweals/busybox.git] / util-linux / fdisk.c
1 /* vi: set sw=4 ts=4: */
2 /* fdisk.c -- Partition table manipulator for Linux.
3  *
4  * Copyright (C) 1992  A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5  * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
6  *
7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8  */
9
10 /* 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         } while (!isdigit(*line_ptr));
1226         return atoi(line_ptr);
1227 }
1228
1229 static void
1230 xbsd_edit_disklabel(void)
1231 {
1232         struct xbsd_disklabel *d;
1233
1234         d = &xbsd_dlabel;
1235
1236 #if defined (__alpha__) || defined (__ia64__)
1237         d->d_secsize    = (u_long) edit_int((u_long) d->d_secsize     ,_("bytes/sector"));
1238         d->d_nsectors   = (u_long) edit_int((u_long) d->d_nsectors    ,_("sectors/track"));
1239         d->d_ntracks    = (u_long) edit_int((u_long) d->d_ntracks     ,_("tracks/cylinder"));
1240         d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders  ,_("cylinders"));
1241 #endif
1242
1243   /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1244         while (1) {
1245                 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1246                                 _("sectors/cylinder"));
1247                 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1248                         break;
1249
1250                 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1251         }
1252         d->d_rpm        = (u_short) edit_int((u_short) d->d_rpm       ,_("rpm"));
1253         d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1254         d->d_trackskew  = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1255         d->d_cylskew    = (u_short) edit_int((u_short) d->d_cylskew   ,_("cylinderskew"));
1256         d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch  ,_("headswitch"));
1257         d->d_trkseek    = (u_long) edit_int((u_long) d->d_trkseek     ,_("track-to-track seek"));
1258
1259         d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
1260 }
1261
1262 static int
1263 xbsd_get_bootstrap (char *path, void *ptr, int size)
1264 {
1265         int fdb;
1266
1267         if ((fdb = open (path, O_RDONLY)) < 0) {
1268                 perror(path);
1269                 return 0;
1270         }
1271         if (read(fdb, ptr, size) < 0) {
1272                 perror(path);
1273                 close(fdb);
1274                 return 0;
1275         }
1276         printf(" ... %s\n", path);
1277         close(fdb);
1278         return 1;
1279 }
1280
1281 static void
1282 sync_disks(void)
1283 {
1284         printf(_("\nSyncing disks.\n"));
1285         sync();
1286         sleep(4); /* What? */
1287 }
1288
1289 static void
1290 xbsd_write_bootstrap(void)
1291 {
1292         char *bootdir = BSD_LINUX_BOOTDIR;
1293         char path[MAXPATHLEN];
1294         char *dkbasename;
1295         struct xbsd_disklabel dl;
1296         char *d, *p, *e;
1297         int sector;
1298
1299         if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1300                 dkbasename = "sd";
1301         else
1302                 dkbasename = "wd";
1303
1304         printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1305                 dkbasename, dkbasename, dkbasename);
1306         if (read_line()) {
1307                 line_ptr[strlen(line_ptr)-1] = '\0';
1308                 dkbasename = line_ptr;
1309         }
1310         snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1311         if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1312                 return;
1313
1314 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1315         d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1316         memmove(&dl, d, sizeof(struct xbsd_disklabel));
1317
1318 /* The disklabel will be overwritten by 0's from bootxx anyway */
1319         memset(d, 0, sizeof(struct xbsd_disklabel));
1320
1321         snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1322         if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1323                           (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1324                 return;
1325
1326         e = d + sizeof(struct xbsd_disklabel);
1327         for (p = d; p < e; p++)
1328                 if (*p) {
1329                         fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1330                         exit(EXIT_FAILURE);
1331                 }
1332
1333         memmove(d, &dl, sizeof(struct xbsd_disklabel));
1334
1335 #if defined (__powerpc__) || defined (__hppa__)
1336         sector = 0;
1337 #elif defined (__alpha__)
1338         sector = 0;
1339         alpha_bootblock_checksum(disklabelbuffer);
1340 #else
1341         sector = get_start_sect(xbsd_part);
1342 #endif
1343
1344         if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1345                 fdisk_fatal(unable_to_seek);
1346         if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1347                 fdisk_fatal(unable_to_write);
1348
1349 #if defined (__alpha__)
1350         printf(_("Bootstrap installed on %s.\n"), disk_device);
1351 #else
1352         printf(_("Bootstrap installed on %s.\n"),
1353                 partname (disk_device, xbsd_part_index+1, 0));
1354 #endif
1355
1356         sync_disks();
1357 }
1358
1359 static void
1360 xbsd_change_fstype(void)
1361 {
1362         int i;
1363
1364         i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1365         xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
1366 }
1367
1368 static int
1369 xbsd_get_part_index(int max)
1370 {
1371         char prompt[256];
1372         char l;
1373
1374         snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1375         do
1376                         l = tolower(read_char(prompt));
1377         while (l < 'a' || l > 'a' + max - 1);
1378         return l - 'a';
1379 }
1380
1381 static int
1382 xbsd_check_new_partition(int *i)
1383 {
1384         /* room for more? various BSD flavours have different maxima */
1385         if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1386                 int t;
1387
1388                 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1389                         if (xbsd_dlabel.d_partitions[t].p_size == 0)
1390                                 break;
1391
1392                 if (t == BSD_MAXPARTITIONS) {
1393                         fprintf(stderr, _("The maximum number of partitions "
1394                                            "has been created\n"));
1395                         return 0;
1396                 }
1397         }
1398
1399         *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1400
1401         if (*i >= xbsd_dlabel.d_npartitions)
1402                 xbsd_dlabel.d_npartitions = (*i) + 1;
1403
1404         if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1405                 fprintf(stderr, _("This partition already exists.\n"));
1406                 return 0;
1407         }
1408
1409         return 1;
1410 }
1411
1412 static void
1413 xbsd_list_types(void)
1414 {
1415         list_types(xbsd_fstypes);
1416 }
1417
1418 static u_short
1419 xbsd_dkcksum(struct xbsd_disklabel *lp)
1420 {
1421         u_short *start, *end;
1422         u_short sum = 0;
1423
1424         start = (u_short *) lp;
1425         end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1426         while (start < end)
1427                 sum ^= *start++;
1428         return sum;
1429 }
1430
1431 static int
1432 xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1433 {
1434         struct xbsd_partition *pp;
1435
1436         get_geometry();
1437         memset(d, 0, sizeof(struct xbsd_disklabel));
1438
1439         d->d_magic = BSD_DISKMAGIC;
1440
1441         if (strncmp(disk_device, "/dev/sd", 7) == 0)
1442                 d->d_type = BSD_DTYPE_SCSI;
1443         else
1444                 d->d_type = BSD_DTYPE_ST506;
1445
1446 #if !defined (__alpha__)
1447         d->d_flags = BSD_D_DOSPART;
1448 #else
1449         d->d_flags = 0;
1450 #endif
1451         d->d_secsize = SECTOR_SIZE;           /* bytes/sector  */
1452         d->d_nsectors = sectors;            /* sectors/track */
1453         d->d_ntracks = heads;               /* tracks/cylinder (heads) */
1454         d->d_ncylinders = cylinders;
1455         d->d_secpercyl  = sectors * heads;/* sectors/cylinder */
1456         if (d->d_secpercyl == 0)
1457                 d->d_secpercyl = 1;           /* avoid segfaults */
1458         d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
1459
1460         d->d_rpm = 3600;
1461         d->d_interleave = 1;
1462         d->d_trackskew = 0;
1463         d->d_cylskew = 0;
1464         d->d_headswitch = 0;
1465         d->d_trkseek = 0;
1466
1467         d->d_magic2 = BSD_DISKMAGIC;
1468         d->d_bbsize = BSD_BBSIZE;
1469         d->d_sbsize = BSD_SBSIZE;
1470
1471 #if !defined (__alpha__)
1472         d->d_npartitions = 4;
1473         pp = &d->d_partitions[2];             /* Partition C should be
1474                                                    the NetBSD partition */
1475         pp->p_offset = get_start_sect(p);
1476         pp->p_size   = get_nr_sects(p);
1477         pp->p_fstype = BSD_FS_UNUSED;
1478         pp = &d->d_partitions[3];             /* Partition D should be
1479                                                    the whole disk */
1480         pp->p_offset = 0;
1481         pp->p_size   = d->d_secperunit;
1482         pp->p_fstype = BSD_FS_UNUSED;
1483 #elif defined (__alpha__)
1484         d->d_npartitions = 3;
1485         pp = &d->d_partitions[2];             /* Partition C should be
1486                                                    the whole disk */
1487         pp->p_offset = 0;
1488         pp->p_size   = d->d_secperunit;
1489         pp->p_fstype = BSD_FS_UNUSED;
1490 #endif
1491
1492         return 1;
1493 }
1494
1495 /*
1496  * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1497  * If it has the right magic, return 1.
1498  */
1499 static int
1500 xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1501 {
1502         int t, sector;
1503
1504         /* p is used only to get the starting sector */
1505 #if !defined (__alpha__)
1506         sector = (p ? get_start_sect(p) : 0);
1507 #elif defined (__alpha__)
1508         sector = 0;
1509 #endif
1510
1511         if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1512                 fdisk_fatal(unable_to_seek);
1513         if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1514                 fdisk_fatal(unable_to_read);
1515
1516         memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1517                    sizeof(struct xbsd_disklabel));
1518
1519         if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
1520                 return 0;
1521
1522         for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1523                 d->d_partitions[t].p_size   = 0;
1524                 d->d_partitions[t].p_offset = 0;
1525                 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
1526         }
1527
1528         if (d->d_npartitions > BSD_MAXPARTITIONS)
1529                 fprintf(stderr, _("Warning: too many partitions "
1530                                 "(%d, maximum is %d).\n"),
1531                         d->d_npartitions, BSD_MAXPARTITIONS);
1532         return 1;
1533 }
1534
1535 static int
1536 xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1537 {
1538         unsigned int sector;
1539
1540 #if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1541         sector = get_start_sect(p) + BSD_LABELSECTOR;
1542 #else
1543         sector = BSD_LABELSECTOR;
1544 #endif
1545
1546         d->d_checksum = 0;
1547         d->d_checksum = xbsd_dkcksum (d);
1548
1549         /* This is necessary if we want to write the bootstrap later,
1550            otherwise we'd write the old disklabel with the bootstrap.
1551         */
1552         memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1553                 d, sizeof(struct xbsd_disklabel));
1554
1555 #if defined (__alpha__) && BSD_LABELSECTOR == 0
1556         alpha_bootblock_checksum (disklabelbuffer);
1557         if (lseek(fd, 0, SEEK_SET) == -1)
1558                 fdisk_fatal(unable_to_seek);
1559         if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1560                 fdisk_fatal(unable_to_write);
1561 #else
1562         if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1563                 fdisk_fatal(unable_to_seek);
1564         if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1565                 fdisk_fatal(unable_to_write);
1566 #endif
1567         sync_disks();
1568         return 1;
1569 }
1570
1571
1572 #if !defined (__alpha__)
1573 static int
1574 xbsd_translate_fstype(int linux_type)
1575 {
1576         switch (linux_type) {
1577         case 0x01: /* DOS 12-bit FAT   */
1578         case 0x04: /* DOS 16-bit <32M  */
1579         case 0x06: /* DOS 16-bit >=32M */
1580         case 0xe1: /* DOS access       */
1581         case 0xe3: /* DOS R/O          */
1582         case 0xf2: /* DOS secondary    */
1583                 return BSD_FS_MSDOS;
1584         case 0x07: /* OS/2 HPFS        */
1585                 return BSD_FS_HPFS;
1586         default:
1587                 return BSD_FS_OTHER;
1588         }
1589 }
1590
1591 static void
1592 xbsd_link_part(void)
1593 {
1594         int k, i;
1595         struct partition *p;
1596
1597         k = get_partition(1, partitions);
1598
1599         if (!xbsd_check_new_partition(&i))
1600                 return;
1601
1602         p = get_part_table(k);
1603
1604         xbsd_dlabel.d_partitions[i].p_size   = get_nr_sects(p);
1605         xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1606         xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1607 }
1608 #endif
1609
1610 #if defined (__alpha__)
1611
1612 #if !defined(__GLIBC__)
1613 typedef unsigned long long uint64_t;
1614 #endif
1615
1616 static void
1617 alpha_bootblock_checksum(char *boot)
1618 {
1619         uint64_t *dp, sum;
1620         int i;
1621
1622         dp = (uint64_t *)boot;
1623         sum = 0;
1624         for (i = 0; i < 63; i++)
1625                 sum += dp[i];
1626         dp[63] = sum;
1627 }
1628 #endif /* __alpha__ */
1629
1630 #endif /* OSF_LABEL */
1631
1632 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1633 static unsigned short
1634 __swap16(unsigned short x)
1635 {
1636         return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
1637 }
1638
1639 static uint32_t
1640 __swap32(uint32_t x)
1641 {
1642         return (((x & 0xFF) << 24) |
1643                 ((x & 0xFF00) << 8) |
1644                 ((x & 0xFF0000) >> 8) |
1645                 ((x & 0xFF000000) >> 24));
1646 }
1647 #endif
1648
1649 #ifdef CONFIG_FEATURE_SGI_LABEL
1650 /*
1651  *
1652  * fdisksgilabel.c
1653  *
1654  * Copyright (C) Andreas Neuper, Sep 1998.
1655  *      This file may be modified and redistributed under
1656  *      the terms of the GNU Public License.
1657  *
1658  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1659  *      Internationalization
1660  */
1661
1662
1663 static int sgi_other_endian;
1664 static int debug;
1665 static short sgi_volumes = 1;
1666
1667 /*
1668  * only dealing with free blocks here
1669  */
1670
1671 typedef struct {
1672         unsigned int first;
1673         unsigned int last;
1674 } freeblocks;
1675 static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1676
1677 static void
1678 setfreelist(int i, unsigned int f, unsigned int l)
1679 {
1680         freelist[i].first = f;
1681         freelist[i].last = l;
1682 }
1683
1684 static void
1685 add2freelist(unsigned int f, unsigned int l)
1686 {
1687         int i;
1688         for (i = 0; i < 17 ; i++)
1689                 if (freelist[i].last == 0)
1690                         break;
1691         setfreelist(i, f, l);
1692 }
1693
1694 static void
1695 clearfreelist(void)
1696 {
1697         int i;
1698
1699         for (i = 0; i < 17 ; i++)
1700                 setfreelist(i, 0, 0);
1701 }
1702
1703 static unsigned int
1704 isinfreelist(unsigned int b)
1705 {
1706         int i;
1707
1708         for (i = 0; i < 17 ; i++)
1709                 if (freelist[i].first <= b && freelist[i].last >= b)
1710                         return freelist[i].last;
1711         return 0;
1712 }
1713         /* return last vacant block of this stride (never 0). */
1714         /* the '>=' is not quite correct, but simplifies the code */
1715 /*
1716  * end of free blocks section
1717  */
1718
1719 static const struct systypes sgi_sys_types[] = {
1720 /* SGI_VOLHDR   */      { "\x00" "SGI volhdr"   },
1721 /* 0x01         */      { "\x01" "SGI trkrepl"  },
1722 /* 0x02         */      { "\x02" "SGI secrepl"  },
1723 /* SGI_SWAP     */      { "\x03" "SGI raw"      },
1724 /* 0x04         */      { "\x04" "SGI bsd"      },
1725 /* 0x05         */      { "\x05" "SGI sysv"     },
1726 /* ENTIRE_DISK  */      { "\x06" "SGI volume"   },
1727 /* SGI_EFS      */      { "\x07" "SGI efs"      },
1728 /* 0x08         */      { "\x08" "SGI lvol"     },
1729 /* 0x09         */      { "\x09" "SGI rlvol"    },
1730 /* SGI_XFS      */      { "\x0a" "SGI xfs"      },
1731 /* SGI_XFSLOG   */      { "\x0b" "SGI xfslog"   },
1732 /* SGI_XLV      */      { "\x0c" "SGI xlv"      },
1733 /* SGI_XVM      */      { "\x0d" "SGI xvm"      },
1734 /* LINUX_SWAP   */      { "\x82" "Linux swap"   },
1735 /* LINUX_NATIVE */      { "\x83" "Linux native" },
1736 /* LINUX_LVM    */      { "\x8d" "Linux LVM"    },
1737 /* LINUX_RAID   */      { "\xfd" "Linux RAID"   },
1738                         { NULL             }
1739 };
1740
1741
1742 static int
1743 sgi_get_nsect(void)
1744 {
1745         return SGI_SSWAP16(sgilabel->devparam.nsect);
1746 }
1747
1748 static int
1749 sgi_get_ntrks(void)
1750 {
1751         return SGI_SSWAP16(sgilabel->devparam.ntrks);
1752 }
1753
1754 static unsigned int
1755 two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1756 {
1757         int i = 0;
1758         unsigned int sum = 0;
1759
1760         size /= sizeof(unsigned int);
1761         for (i = 0; i < size; i++)
1762                 sum -= SGI_SSWAP32(base[i]);
1763         return sum;
1764 }
1765
1766 static int
1767 check_sgi_label(void)
1768 {
1769         if (sizeof(sgilabel) > 512) {
1770                 fprintf(stderr,
1771                         _("According to MIPS Computer Systems, Inc the "
1772                         "Label must not contain more than 512 bytes\n"));
1773                 exit(1);
1774         }
1775
1776         if (sgilabel->magic != SGI_LABEL_MAGIC
1777          && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1778                 current_label_type = label_dos;
1779                 return 0;
1780         }
1781
1782         sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1783         /*
1784          * test for correct checksum
1785          */
1786         if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1787                                 sizeof(*sgilabel))) {
1788                 fprintf(stderr,
1789                         _("Detected sgi disklabel with wrong checksum.\n"));
1790         }
1791         update_units();
1792         current_label_type = label_sgi;
1793         partitions = 16;
1794         sgi_volumes = 15;
1795         return 1;
1796 }
1797
1798 static unsigned int
1799 sgi_get_start_sector(int i)
1800 {
1801         return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1802 }
1803
1804 static unsigned int
1805 sgi_get_num_sectors(int i)
1806 {
1807         return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1808 }
1809
1810 static int
1811 sgi_get_sysid(int i)
1812 {
1813         return SGI_SSWAP32(sgilabel->partitions[i].id);
1814 }
1815
1816 static int
1817 sgi_get_bootpartition(void)
1818 {
1819         return SGI_SSWAP16(sgilabel->boot_part);
1820 }
1821
1822 static int
1823 sgi_get_swappartition(void)
1824 {
1825         return SGI_SSWAP16(sgilabel->swap_part);
1826 }
1827
1828 static void
1829 sgi_list_table(int xtra)
1830 {
1831         int i, w, wd;
1832         int kpi = 0;                /* kernel partition ID */
1833
1834         if(xtra) {
1835                 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1836                         "%d cylinders, %d physical cylinders\n"
1837                         "%d extra sects/cyl, interleave %d:1\n"
1838                         "%s\n"
1839                         "Units = %s of %d * 512 bytes\n\n"),
1840                         disk_device, heads, sectors, cylinders,
1841                         SGI_SSWAP16(sgiparam.pcylcount),
1842                         SGI_SSWAP16(sgiparam.sparecyl),
1843                         SGI_SSWAP16(sgiparam.ilfact),
1844                         (char *)sgilabel,
1845                         str_units(PLURAL), units_per_sector);
1846         } else {
1847                 printf( _("\nDisk %s (SGI disk label): "
1848                         "%d heads, %d sectors, %d cylinders\n"
1849                         "Units = %s of %d * 512 bytes\n\n"),
1850                         disk_device, heads, sectors, cylinders,
1851                         str_units(PLURAL), units_per_sector );
1852         }
1853
1854         w = strlen(disk_device);
1855         wd = strlen(_("Device"));
1856         if (w < wd)
1857         w = wd;
1858
1859         printf(_("----- partitions -----\n"
1860                 "Pt# %*s  Info     Start       End   Sectors  Id  System\n"),
1861                 w + 2, _("Device"));
1862         for (i = 0 ; i < partitions; i++) {
1863                 if( sgi_get_num_sectors(i) || debug ) {
1864                         uint32_t start = sgi_get_start_sector(i);
1865                         uint32_t len = sgi_get_num_sectors(i);
1866                         kpi++;              /* only count nonempty partitions */
1867                         printf(
1868                         "%2d: %s %4s %9ld %9ld %9ld  %2x  %s\n",
1869 /* fdisk part number */ i+1,
1870 /* device */            partname(disk_device, kpi, w+3),
1871 /* flags */             (sgi_get_swappartition() == i) ? "swap" :
1872 /* flags */             (sgi_get_bootpartition() == i) ? "boot" : "    ",
1873 /* start */             (long) scround(start),
1874 /* end */               (long) scround(start+len)-1,
1875 /* no odd flag on end */(long) len,
1876 /* type id */           sgi_get_sysid(i),
1877 /* type name */         partition_type(sgi_get_sysid(i)));
1878                 }
1879         }
1880         printf(_("----- Bootinfo -----\nBootfile: %s\n"
1881                 "----- Directory Entries -----\n"),
1882                 sgilabel->boot_file);
1883         for (i = 0 ; i < sgi_volumes; i++) {
1884                 if (sgilabel->directory[i].vol_file_size) {
1885                         uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1886                         uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1887                         unsigned char *name = sgilabel->directory[i].vol_file_name;
1888
1889                         printf(_("%2d: %-10s sector%5u size%8u\n"),
1890                                 i, (char*)name, (unsigned int) start, (unsigned int) len);
1891                 }
1892         }
1893 }
1894
1895 static void
1896 sgi_set_bootpartition(int i)
1897 {
1898         sgilabel->boot_part = SGI_SSWAP16(((short)i));
1899 }
1900
1901 static unsigned int
1902 sgi_get_lastblock(void)
1903 {
1904         return heads * sectors * cylinders;
1905 }
1906
1907 static void
1908 sgi_set_swappartition(int i)
1909 {
1910         sgilabel->swap_part = SGI_SSWAP16(((short)i));
1911 }
1912
1913 static int
1914 sgi_check_bootfile(const char* aFile)
1915 {
1916         if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1917                 printf(_("\nInvalid Bootfile!\n"
1918                         "\tThe bootfile must be an absolute non-zero pathname,\n"
1919                         "\te.g. \"/unix\" or \"/unix.save\".\n"));
1920                 return 0;
1921         } else {
1922                 if (strlen(aFile) > 16) {
1923                         printf(_("\n\tName of Bootfile too long:  "
1924                                 "16 bytes maximum.\n"));
1925                         return 0;
1926                 } else {
1927                         if (aFile[0] != '/') {
1928                                 printf(_("\n\tBootfile must have a "
1929                                         "fully qualified pathname.\n"));
1930                                 return 0;
1931                         }
1932                 }
1933         }
1934         if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
1935                 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1936                          "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
1937                 /* filename is correct and did change */
1938                 return 1;
1939         }
1940         return 0;   /* filename did not change */
1941 }
1942
1943 static const char *
1944 sgi_get_bootfile(void)
1945 {
1946         return (char*)sgilabel->boot_file;
1947 }
1948
1949 static void
1950 sgi_set_bootfile(const char* aFile)
1951 {
1952         int i = 0;
1953
1954         if (sgi_check_bootfile(aFile)) {
1955                 while (i < 16) {
1956                         if ((aFile[i] != '\n')  /* in principle caught again by next line */
1957                          && (strlen(aFile) > i))
1958                                 sgilabel->boot_file[i] = aFile[i];
1959                         else
1960                                 sgilabel->boot_file[i] = 0;
1961                         i++;
1962                 }
1963                 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
1964         }
1965 }
1966
1967 static void
1968 create_sgiinfo(void)
1969 {
1970         /* I keep SGI's habit to write the sgilabel to the second block */
1971         sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1972         sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1973         strcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel");
1974 }
1975
1976 static sgiinfo *fill_sgiinfo(void);
1977
1978 static void
1979 sgi_write_table(void)
1980 {
1981         sgilabel->csum = 0;
1982         sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1983                         (unsigned int*)sgilabel, sizeof(*sgilabel)));
1984         assert(two_s_complement_32bit_sum(
1985                 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
1986
1987         if (lseek(fd, 0, SEEK_SET) < 0)
1988                 fdisk_fatal(unable_to_seek);
1989         if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1990                 fdisk_fatal(unable_to_write);
1991         if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
1992                 /*
1993                  * keep this habit of first writing the "sgilabel".
1994                  * I never tested whether it works without (AN 981002).
1995                  */
1996                 sgiinfo *info = fill_sgiinfo();
1997                 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
1998                 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
1999                         fdisk_fatal(unable_to_seek);
2000                 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2001                         fdisk_fatal(unable_to_write);
2002                 free(info);
2003         }
2004 }
2005
2006 static int
2007 compare_start(int *x, int *y)
2008 {
2009         /*
2010          * sort according to start sectors
2011          * and prefers largest partition:
2012          * entry zero is entire disk entry
2013          */
2014         unsigned int i = *x;
2015         unsigned int j = *y;
2016         unsigned int a = sgi_get_start_sector(i);
2017         unsigned int b = sgi_get_start_sector(j);
2018         unsigned int c = sgi_get_num_sectors(i);
2019         unsigned int d = sgi_get_num_sectors(j);
2020
2021         if (a == b)
2022                 return (d > c) ? 1 : (d == c) ? 0 : -1;
2023         return (a > b) ? 1 : -1;
2024 }
2025
2026
2027 static int
2028 verify_sgi(int verbose)
2029 {
2030         int Index[16];      /* list of valid partitions */
2031         int sortcount = 0;  /* number of used partitions, i.e. non-zero lengths */
2032         int entire = 0, i = 0;
2033         unsigned int start = 0;
2034         long long gap = 0;      /* count unused blocks */
2035         unsigned int lastblock = sgi_get_lastblock();
2036
2037         clearfreelist();
2038         for (i = 0; i < 16; i++) {
2039                 if (sgi_get_num_sectors(i) != 0) {
2040                         Index[sortcount++] = i;
2041                         if (sgi_get_sysid(i) == ENTIRE_DISK) {
2042                                 if (entire++ == 1) {
2043                                         if (verbose)
2044                                                 printf(_("More than one entire disk entry present.\n"));
2045                                 }
2046                         }
2047                 }
2048         }
2049         if (sortcount == 0) {
2050                 if (verbose)
2051                         printf(_("No partitions defined\n"));
2052                 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2053         }
2054         qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2055         if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2056                 if ((Index[0] != 10) && verbose)
2057                         printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2058                 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2059                         printf(_("The entire disk partition should start "
2060                                 "at block 0,\n"
2061                                 "not at diskblock %d.\n"),
2062                 sgi_get_start_sector(Index[0]));
2063                 if (debug)      /* I do not understand how some disks fulfil it */
2064                         if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2065                                 printf(_("The entire disk partition is only %d diskblock large,\n"
2066                                         "but the disk is %d diskblocks long.\n"),
2067                 sgi_get_num_sectors(Index[0]), lastblock);
2068                 lastblock = sgi_get_num_sectors(Index[0]);
2069         } else {
2070                 if (verbose)
2071                         printf(_("One Partition (#11) should cover the entire disk.\n"));
2072                 if (debug > 2)
2073                         printf("sysid=%d\tpartition=%d\n",
2074                                 sgi_get_sysid(Index[0]), Index[0]+1);
2075         }
2076         for (i = 1, start = 0; i < sortcount; i++) {
2077                 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2078
2079                 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2080                         if (debug)      /* I do not understand how some disks fulfil it */
2081                                 if (verbose)
2082                                         printf(_("Partition %d does not start on cylinder boundary.\n"),
2083                                                 Index[i]+1);
2084                 }
2085                 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2086                         if (debug)      /* I do not understand how some disks fulfil it */
2087                                 if (verbose)
2088                                         printf(_("Partition %d does not end on cylinder boundary.\n"),
2089                                                 Index[i]+1);
2090                 }
2091                 /* We cannot handle several "entire disk" entries. */
2092                 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2093                 if (start > sgi_get_start_sector(Index[i])) {
2094                         if (verbose)
2095                                 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2096                                         Index[i-1]+1, Index[i]+1,
2097                                         start - sgi_get_start_sector(Index[i]));
2098                         if (gap >  0) gap = -gap;
2099                         if (gap == 0) gap = -1;
2100                 }
2101                 if (start < sgi_get_start_sector(Index[i])) {
2102                         if (verbose)
2103                                 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2104                                         sgi_get_start_sector(Index[i]) - start,
2105                                         start, sgi_get_start_sector(Index[i])-1);
2106                         gap += sgi_get_start_sector(Index[i]) - start;
2107                         add2freelist(start, sgi_get_start_sector(Index[i]));
2108                 }
2109                 start = sgi_get_start_sector(Index[i])
2110                            + sgi_get_num_sectors(Index[i]);
2111                 if (debug > 1) {
2112                         if (verbose)
2113                                 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2114                                         sgi_get_start_sector(Index[i]),
2115                                         sgi_get_num_sectors(Index[i]),
2116                                         sgi_get_sysid(Index[i]));
2117                 }
2118         }
2119         if (start < lastblock) {
2120                 if (verbose)
2121                         printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2122                                 lastblock - start, start, lastblock-1);
2123                 gap += lastblock - start;
2124                 add2freelist(start, lastblock);
2125         }
2126         /*
2127          * Done with arithmetics
2128          * Go for details now
2129          */
2130         if (verbose) {
2131                 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2132                         printf(_("\nThe boot partition does not exist.\n"));
2133                 }
2134                 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2135                         printf(_("\nThe swap partition does not exist.\n"));
2136                 } else {
2137                         if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2138                          && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2139                                 printf(_("\nThe swap partition has no swap type.\n"));
2140                 }
2141                 if (sgi_check_bootfile("/unix"))
2142                         printf(_("\tYou have chosen an unusual boot file name.\n"));
2143         }
2144         return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
2145 }
2146
2147 static int
2148 sgi_gaps(void)
2149 {
2150         /*
2151          * returned value is:
2152          *  = 0 : disk is properly filled to the rim
2153          *  < 0 : there is an overlap
2154          *  > 0 : there is still some vacant space
2155          */
2156         return verify_sgi(0);
2157 }
2158
2159 static void
2160 sgi_change_sysid(int i, int sys)
2161 {
2162         if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2163                 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2164                 return;
2165         }
2166         if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2167          && (sgi_get_start_sector(i) < 1) ) {
2168                 read_chars(
2169                         _("It is highly recommended that the partition at offset 0\n"
2170                         "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2171                         "retrieve from its directory standalone tools like sash and fx.\n"
2172                         "Only the \"SGI volume\" entire disk section may violate this.\n"
2173                         "Type YES if you are sure about tagging this partition differently.\n"));
2174                 if (strcmp(line_ptr, _("YES\n")))
2175                         return;
2176         }
2177         sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2178 }
2179
2180 /* returns partition index of first entry marked as entire disk */
2181 static int
2182 sgi_entire(void)
2183 {
2184         int i;
2185
2186         for (i = 0; i < 16; i++)
2187                 if (sgi_get_sysid(i) == SGI_VOLUME)
2188                         return i;
2189         return -1;
2190 }
2191
2192 static void
2193 sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2194 {
2195         sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2196         sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2197         sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2198         set_changed(i);
2199         if (sgi_gaps() < 0)     /* rebuild freelist */
2200                 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2201 }
2202
2203 static void
2204 sgi_set_entire(void)
2205 {
2206         int n;
2207
2208         for (n = 10; n < partitions; n++) {
2209                 if(!sgi_get_num_sectors(n) ) {
2210                         sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2211                         break;
2212                 }
2213         }
2214 }
2215
2216 static void
2217 sgi_set_volhdr(void)
2218 {
2219         int n;
2220
2221         for (n = 8; n < partitions; n++) {
2222         if (!sgi_get_num_sectors(n)) {
2223                 /*
2224                  * 5 cylinders is an arbitrary value I like
2225                  * IRIX 5.3 stored files in the volume header
2226                  * (like sash, symmon, fx, ide) with ca. 3200
2227                  * sectors.
2228                  */
2229                 if (heads * sectors * 5 < sgi_get_lastblock())
2230                         sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2231                         break;
2232                 }
2233         }
2234 }
2235
2236 static void
2237 sgi_delete_partition(int i)
2238 {
2239         sgi_set_partition(i, 0, 0, 0);
2240 }
2241
2242 static void
2243 sgi_add_partition(int n, int sys)
2244 {
2245         char mesg[256];
2246         unsigned int first = 0, last = 0;
2247
2248         if (n == 10) {
2249                 sys = SGI_VOLUME;
2250         } else if (n == 8) {
2251                 sys = 0;
2252         }
2253         if(sgi_get_num_sectors(n)) {
2254                 printf(_("Partition %d is already defined.  Delete "
2255                         "it before re-adding it.\n"), n + 1);
2256                 return;
2257         }
2258         if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2259                 printf(_("Attempting to generate entire disk entry automatically.\n"));
2260                 sgi_set_entire();
2261                 sgi_set_volhdr();
2262         }
2263         if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2264                 printf(_("The entire disk is already covered with partitions.\n"));
2265                 return;
2266         }
2267         if (sgi_gaps() < 0) {
2268                 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2269                 return;
2270         }
2271         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2272         while (1) {
2273                 if(sys == SGI_VOLUME) {
2274                         last = sgi_get_lastblock();
2275                         first = read_int(0, 0, last-1, 0, mesg);
2276                         if (first != 0) {
2277                                 printf(_("It is highly recommended that eleventh partition\n"
2278                                                 "covers the entire disk and is of type `SGI volume'\n"));
2279                         }
2280                 } else {
2281                         first = freelist[0].first;
2282                         last  = freelist[0].last;
2283                         first = read_int(scround(first), scround(first), scround(last)-1,
2284                                 0, mesg);
2285                 }
2286                 if (display_in_cyl_units)
2287                         first *= units_per_sector;
2288                 else
2289                         first = first; /* align to cylinder if you know how ... */
2290                 if(!last )
2291                         last = isinfreelist(first);
2292                 if(last == 0) {
2293                         printf(_("You will get a partition overlap on the disk. "
2294                                 "Fix it first!\n"));
2295                 } else
2296                         break;
2297         }
2298         snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2299         last = read_int(scround(first), scround(last)-1, scround(last)-1,
2300                         scround(first), mesg)+1;
2301         if (display_in_cyl_units)
2302                 last *= units_per_sector;
2303         else
2304                 last = last; /* align to cylinder if You know how ... */
2305         if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2306                 printf(_("It is highly recommended that eleventh partition\n"
2307                         "covers the entire disk and is of type `SGI volume'\n"));
2308         sgi_set_partition(n, first, last-first, sys);
2309 }
2310
2311 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
2312 static void
2313 create_sgilabel(void)
2314 {
2315         struct hd_geometry geometry;
2316         struct {
2317                 unsigned int start;
2318                 unsigned int nsect;
2319                 int sysid;
2320         } old[4];
2321         int i = 0;
2322         long longsectors;               /* the number of sectors on the device */
2323         int res;                        /* the result from the ioctl */
2324         int sec_fac;                    /* the sector factor */
2325
2326         sec_fac = sector_size / 512;    /* determine the sector factor */
2327
2328         fprintf( stderr,
2329                 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2330                 "until you decide to write them. After that, of course, the previous\n"
2331                 "content will be unrecoverably lost.\n\n"));
2332
2333         sgi_other_endian = (BB_LITTLE_ENDIAN);
2334         res = ioctl(fd, BLKGETSIZE, &longsectors);
2335         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2336                 heads = geometry.heads;
2337                 sectors = geometry.sectors;
2338                 if (res == 0) {
2339                         /* the get device size ioctl was successful */
2340                         cylinders = longsectors / (heads * sectors);
2341                         cylinders /= sec_fac;
2342                 } else {
2343                         /* otherwise print error and use truncated version */
2344                         cylinders = geometry.cylinders;
2345                         fprintf(stderr,
2346                                 _("Warning:  BLKGETSIZE ioctl failed on %s.  "
2347                                 "Using geometry cylinder value of %d.\n"
2348                                 "This value may be truncated for devices"
2349                                 " > 33.8 GB.\n"), disk_device, cylinders);
2350                 }
2351         }
2352         for (i = 0; i < 4; i++) {
2353                 old[i].sysid = 0;
2354                 if (valid_part_table_flag(MBRbuffer)) {
2355                         if(get_part_table(i)->sys_ind) {
2356                                 old[i].sysid = get_part_table(i)->sys_ind;
2357                                 old[i].start = get_start_sect(get_part_table(i));
2358                                 old[i].nsect = get_nr_sects(get_part_table(i));
2359                                 printf(_("Trying to keep parameters of partition %d.\n"), i);
2360                                 if (debug)
2361                                         printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2362                                 old[i].sysid, old[i].start, old[i].nsect);
2363                         }
2364                 }
2365         }
2366
2367         memset(MBRbuffer, 0, sizeof(MBRbuffer));
2368         sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2369         sgilabel->boot_part = SGI_SSWAP16(0);
2370         sgilabel->swap_part = SGI_SSWAP16(1);
2371
2372         /* sizeof(sgilabel->boot_file) = 16 > 6 */
2373         memset(sgilabel->boot_file, 0, 16);
2374         strcpy((char*)sgilabel->boot_file, "/unix");
2375
2376         sgilabel->devparam.skew                     = (0);
2377         sgilabel->devparam.gap1                     = (0);
2378         sgilabel->devparam.gap2                     = (0);
2379         sgilabel->devparam.sparecyl                 = (0);
2380         sgilabel->devparam.pcylcount                = SGI_SSWAP16(geometry.cylinders);
2381         sgilabel->devparam.head_vol0                = SGI_SSWAP16(0);
2382         sgilabel->devparam.ntrks                    = SGI_SSWAP16(geometry.heads);
2383                                                 /* tracks/cylinder (heads) */
2384         sgilabel->devparam.cmd_tag_queue_depth      = (0);
2385         sgilabel->devparam.unused0                  = (0);
2386         sgilabel->devparam.unused1                  = SGI_SSWAP16(0);
2387         sgilabel->devparam.nsect                    = SGI_SSWAP16(geometry.sectors);
2388                                                 /* sectors/track */
2389         sgilabel->devparam.bytes                    = SGI_SSWAP16(512);
2390         sgilabel->devparam.ilfact                   = SGI_SSWAP16(1);
2391         sgilabel->devparam.flags                    = SGI_SSWAP32(TRACK_FWD|
2392                                                         IGNORE_ERRORS|RESEEK);
2393         sgilabel->devparam.datarate                 = SGI_SSWAP32(0);
2394         sgilabel->devparam.retries_on_error         = SGI_SSWAP32(1);
2395         sgilabel->devparam.ms_per_word              = SGI_SSWAP32(0);
2396         sgilabel->devparam.xylogics_gap1            = SGI_SSWAP16(0);
2397         sgilabel->devparam.xylogics_syncdelay       = SGI_SSWAP16(0);
2398         sgilabel->devparam.xylogics_readdelay       = SGI_SSWAP16(0);
2399         sgilabel->devparam.xylogics_gap2            = SGI_SSWAP16(0);
2400         sgilabel->devparam.xylogics_readgate        = SGI_SSWAP16(0);
2401         sgilabel->devparam.xylogics_writecont       = SGI_SSWAP16(0);
2402         memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2403         memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2404         current_label_type = label_sgi;
2405         partitions = 16;
2406         sgi_volumes = 15;
2407         sgi_set_entire();
2408         sgi_set_volhdr();
2409         for (i = 0; i < 4; i++) {
2410                 if(old[i].sysid) {
2411                         sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2412                 }
2413         }
2414 }
2415
2416 static void
2417 sgi_set_xcyl(void)
2418 {
2419         /* do nothing in the beginning */
2420 }
2421 #endif /* CONFIG_FEATURE_FDISK_ADVANCED */
2422
2423 /* _____________________________________________________________
2424  */
2425
2426 static sgiinfo *
2427 fill_sgiinfo(void)
2428 {
2429         sgiinfo *info = calloc(1, sizeof(sgiinfo));
2430
2431         info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2432         info->b1 = SGI_SSWAP32(-1);
2433         info->b2 = SGI_SSWAP16(-1);
2434         info->b3 = SGI_SSWAP16(1);
2435         /* You may want to replace this string !!!!!!! */
2436         strcpy( (char*)info->scsi_string, "IBM OEM 0662S12         3 30" );
2437         strcpy( (char*)info->serial, "0000" );
2438         info->check1816 = SGI_SSWAP16(18*256 +16 );
2439         strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2440         return info;
2441 }
2442 #endif /* SGI_LABEL */
2443
2444
2445 #ifdef CONFIG_FEATURE_SUN_LABEL
2446 /*
2447  * fdisksunlabel.c
2448  *
2449  * I think this is mostly, or entirely, due to
2450  *      Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2451  *
2452  * Merged with fdisk for other architectures, aeb, June 1998.
2453  *
2454  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2455  *      Internationalization
2456  */
2457
2458
2459 static int sun_other_endian;
2460 static int scsi_disk;
2461 static int floppy;
2462
2463 #ifndef IDE0_MAJOR
2464 #define IDE0_MAJOR 3
2465 #endif
2466 #ifndef IDE1_MAJOR
2467 #define IDE1_MAJOR 22
2468 #endif
2469
2470 static void
2471 guess_device_type(void)
2472 {
2473         struct stat bootstat;
2474
2475         if (fstat(fd, &bootstat) < 0) {
2476                 scsi_disk = 0;
2477                 floppy = 0;
2478         } else if (S_ISBLK(bootstat.st_mode)
2479                 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2480                     major(bootstat.st_rdev) == IDE1_MAJOR)) {
2481                 scsi_disk = 0;
2482                 floppy = 0;
2483         } else if (S_ISBLK(bootstat.st_mode)
2484                 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
2485                 scsi_disk = 0;
2486                 floppy = 1;
2487         } else {
2488                 scsi_disk = 1;
2489                 floppy = 0;
2490         }
2491 }
2492
2493 static const struct systypes sun_sys_types[] = {
2494         { "\x00" "Empty"        }, /* 0            */
2495         { "\x01" "Boot"         }, /* 1            */
2496         { "\x02" "SunOS root"   }, /* 2            */
2497         { "\x03" "SunOS swap"   }, /* SUNOS_SWAP   */
2498         { "\x04" "SunOS usr"    }, /* 4            */
2499         { "\x05" "Whole disk"   }, /* WHOLE_DISK   */
2500         { "\x06" "SunOS stand"  }, /* 6            */
2501         { "\x07" "SunOS var"    }, /* 7            */
2502         { "\x08" "SunOS home"   }, /* 8            */
2503         { "\x82" "Linux swap"   }, /* LINUX_SWAP   */
2504         { "\x83" "Linux native" }, /* LINUX_NATIVE */
2505         { "\x8e" "Linux LVM"    }, /* 0x8e         */
2506 /* New (2.2.x) raid partition with autodetect using persistent superblock */
2507         { "\xfd" "Linux raid autodetect" }, /* 0xfd         */
2508         { NULL }
2509 };
2510
2511
2512 static void
2513 set_sun_partition(int i, uint start, uint stop, int sysid)
2514 {
2515         sunlabel->infos[i].id = sysid;
2516         sunlabel->partitions[i].start_cylinder =
2517                 SUN_SSWAP32(start / (heads * sectors));
2518         sunlabel->partitions[i].num_sectors =
2519                 SUN_SSWAP32(stop - start);
2520         set_changed(i);
2521 }
2522
2523 static int
2524 check_sun_label(void)
2525 {
2526         unsigned short *ush;
2527         int csum;
2528
2529         if (sunlabel->magic != SUN_LABEL_MAGIC
2530          && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2531                 current_label_type = label_dos;
2532                 sun_other_endian = 0;
2533                 return 0;
2534         }
2535         sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2536         ush = ((unsigned short *) (sunlabel + 1)) - 1;
2537         for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2538         if (csum) {
2539                 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2540                                 "Probably you'll have to set all the values,\n"
2541                                 "e.g. heads, sectors, cylinders and partitions\n"
2542                                 "or force a fresh label (s command in main menu)\n"));
2543         } else {
2544                 heads = SUN_SSWAP16(sunlabel->ntrks);
2545                 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2546                 sectors = SUN_SSWAP16(sunlabel->nsect);
2547         }
2548         update_units();
2549         current_label_type = label_sun;
2550         partitions = 8;
2551         return 1;
2552 }
2553
2554 static const struct sun_predefined_drives {
2555         const char *vendor;
2556         const char *model;
2557         unsigned short sparecyl;
2558         unsigned short ncyl;
2559         unsigned short nacyl;
2560         unsigned short pcylcount;
2561         unsigned short ntrks;
2562         unsigned short nsect;
2563         unsigned short rspeed;
2564 } sun_drives[] = {
2565         { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2566         { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2567         { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2568         { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2569         { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2570         { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2571         { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2572         { "","SUN0104",1,974,2,1019,6,35,3662},
2573         { "","SUN0207",4,1254,2,1272,9,36,3600},
2574         { "","SUN0327",3,1545,2,1549,9,46,3600},
2575         { "","SUN0340",0,1538,2,1544,6,72,4200},
2576         { "","SUN0424",2,1151,2,2500,9,80,4400},
2577         { "","SUN0535",0,1866,2,2500,7,80,5400},
2578         { "","SUN0669",5,1614,2,1632,15,54,3600},
2579         { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2580         { "","SUN1.05",0,2036,2,2038,14,72,5400},
2581         { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2582         { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2583         { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2584 };
2585
2586 static const struct sun_predefined_drives *
2587 sun_autoconfigure_scsi(void)
2588 {
2589         const struct sun_predefined_drives *p = NULL;
2590
2591 #ifdef SCSI_IOCTL_GET_IDLUN
2592         unsigned int id[2];
2593         char buffer[2048];
2594         char buffer2[2048];
2595         FILE *pfd;
2596         char *vendor;
2597         char *model;
2598         char *q;
2599         int i;
2600
2601         if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2602                 sprintf(buffer,
2603                         "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2604                         /* This is very wrong (works only if you have one HBA),
2605                            but I haven't found a way how to get hostno
2606                            from the current kernel */
2607                         0,
2608                         (id[0]>>16) & 0xff,
2609                         id[0] & 0xff,
2610                         (id[0]>>8) & 0xff
2611                 );
2612                 pfd = fopen("/proc/scsi/scsi","r");
2613                 if (pfd) {
2614                         while (fgets(buffer2, 2048, pfd)) {
2615                                 if (!strcmp(buffer, buffer2)) {
2616                                         if (fgets(buffer2,2048,pfd)) {
2617                                                 q = strstr(buffer2,"Vendor: ");
2618                                                 if (q) {
2619                                                         q += 8;
2620                                                         vendor = q;
2621                                                         q = strstr(q," ");
2622                                                         *q++ = 0;   /* truncate vendor name */
2623                                                         q = strstr(q,"Model: ");
2624                                                         if (q) {
2625                                                                 *q = 0;
2626                                                                 q += 7;
2627                                                                 model = q;
2628                                                                 q = strstr(q," Rev: ");
2629                                                                 if (q) {
2630                                                                         *q = 0;
2631                                                                         for (i = 0; i < SIZE(sun_drives); i++) {
2632                                                                                 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2633                                                                                         continue;
2634                                                                                 if (!strstr(model, sun_drives[i].model))
2635                                                                                         continue;
2636                                                                                 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2637                                                                                 p = sun_drives + i;
2638                                                                                 break;
2639                                                                         }
2640                                                                 }
2641                                                         }
2642                                                 }
2643                                         }
2644                                         break;
2645                                 }
2646                         }
2647                         fclose(pfd);
2648                 }
2649         }
2650 #endif
2651         return p;
2652 }
2653
2654 static void
2655 create_sunlabel(void)
2656 {
2657         struct hd_geometry geometry;
2658         unsigned int ndiv;
2659         int i;
2660         unsigned char c;
2661         const struct sun_predefined_drives *p = NULL;
2662
2663         fprintf(stderr,
2664                 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2665                 "until you decide to write them. After that, of course, the previous\n"
2666                 "content won't be recoverable.\n\n"));
2667         sun_other_endian = BB_LITTLE_ENDIAN;
2668         memset(MBRbuffer, 0, sizeof(MBRbuffer));
2669         sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2670         if (!floppy) {
2671                 puts(_("Drive type\n"
2672                  "   ?   auto configure\n"
2673                  "   0   custom (with hardware detected defaults)"));
2674                 for (i = 0; i < SIZE(sun_drives); i++) {
2675                         printf("   %c   %s%s%s\n",
2676                                 i + 'a', sun_drives[i].vendor,
2677                                 (*sun_drives[i].vendor) ? " " : "",
2678                                 sun_drives[i].model);
2679                 }
2680                 while (1) {
2681                         c = read_char(_("Select type (? for auto, 0 for custom): "));
2682                         if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2683                                 p = sun_drives + c - 'a';
2684                                 break;
2685                         } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2686                                 p = sun_drives + c - 'A';
2687                                 break;
2688                         } else if (c == '0') {
2689                                 break;
2690                         } else if (c == '?' && scsi_disk) {
2691                                 p = sun_autoconfigure_scsi();
2692                                 if (!p)
2693                                 printf(_("Autoconfigure failed.\n"));
2694                                 else
2695                                 break;
2696                         }
2697                 }
2698         }
2699         if (!p || floppy) {
2700                 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2701                         heads = geometry.heads;
2702                         sectors = geometry.sectors;
2703                         cylinders = geometry.cylinders;
2704                 } else {
2705                         heads = 0;
2706                         sectors = 0;
2707                         cylinders = 0;
2708                 }
2709                 if (floppy) {
2710                         sunlabel->nacyl = 0;
2711                         sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2712                         sunlabel->rspeed = SUN_SSWAP16(300);
2713                         sunlabel->ilfact = SUN_SSWAP16(1);
2714                         sunlabel->sparecyl = 0;
2715                 } else {
2716                         heads = read_int(1,heads,1024,0,_("Heads"));
2717                         sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2718                 if (cylinders)
2719                         cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2720                 else
2721                         cylinders = read_int(1,0,65535,0,_("Cylinders"));
2722                         sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2723                         sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2724                         sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2725                         sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2726                         sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2727                 }
2728         } else {
2729                 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2730                 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2731                 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2732                 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2733                 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2734                 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2735                 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2736                 sunlabel->ilfact = SUN_SSWAP16(1);
2737                 cylinders = p->ncyl;
2738                 heads = p->ntrks;
2739                 sectors = p->nsect;
2740                 puts(_("You may change all the disk params from the x menu"));
2741         }
2742
2743         snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
2744                 "%s%s%s cyl %d alt %d hd %d sec %d",
2745                 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2746                 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2747                 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2748
2749         sunlabel->ntrks = SUN_SSWAP16(heads);
2750         sunlabel->nsect = SUN_SSWAP16(sectors);
2751         sunlabel->ncyl = SUN_SSWAP16(cylinders);
2752         if (floppy)
2753                 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2754         else {
2755                 if (cylinders * heads * sectors >= 150 * 2048) {
2756                         ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2757                 } else
2758                         ndiv = cylinders * 2 / 3;
2759                 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2760                 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2761                 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2762         }
2763         set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2764         {
2765                 unsigned short *ush = (unsigned short *)sunlabel;
2766                 unsigned short csum = 0;
2767                 while (ush < (unsigned short *)(&sunlabel->csum))
2768                         csum ^= *ush++;
2769                 sunlabel->csum = csum;
2770         }
2771
2772         set_all_unchanged();
2773         set_changed(0);
2774         get_boot(create_empty_sun);
2775 }
2776
2777 static void
2778 toggle_sunflags(int i, unsigned char mask)
2779 {
2780         if (sunlabel->infos[i].flags & mask)
2781                 sunlabel->infos[i].flags &= ~mask;
2782         else
2783                 sunlabel->infos[i].flags |= mask;
2784         set_changed(i);
2785 }
2786
2787 static void
2788 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2789 {
2790         int i, continuous = 1;
2791
2792         *start = 0;
2793         *stop = cylinders * heads * sectors;
2794         for (i = 0; i < partitions; i++) {
2795                 if (sunlabel->partitions[i].num_sectors
2796                  && sunlabel->infos[i].id
2797                  && sunlabel->infos[i].id != WHOLE_DISK) {
2798                         starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2799                         lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2800                         if (continuous) {
2801                                 if (starts[i] == *start)
2802                                         *start += lens[i];
2803                                 else if (starts[i] + lens[i] >= *stop)
2804                                         *stop = starts[i];
2805                                 else
2806                                         continuous = 0;
2807                                         /* There will be probably more gaps
2808                                           than one, so lets check afterwards */
2809                         }
2810                 } else {
2811                         starts[i] = 0;
2812                         lens[i] = 0;
2813                 }
2814         }
2815 }
2816
2817 static uint *verify_sun_starts;
2818
2819 static int
2820 verify_sun_cmp(int *a, int *b)
2821 {
2822         if (*a == -1) return 1;
2823         if (*b == -1) return -1;
2824         if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2825         return -1;
2826 }
2827
2828 static void
2829 verify_sun(void)
2830 {
2831         uint starts[8], lens[8], start, stop;
2832         int i,j,k,starto,endo;
2833         int array[8];
2834
2835         verify_sun_starts = starts;
2836         fetch_sun(starts,lens,&start,&stop);
2837         for (k = 0; k < 7; k++) {
2838                 for (i = 0; i < 8; i++) {
2839                         if (k && (lens[i] % (heads * sectors))) {
2840                                 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2841                         }
2842                         if (lens[i]) {
2843                                 for (j = 0; j < i; j++)
2844                                         if (lens[j]) {
2845                                                 if (starts[j] == starts[i]+lens[i]) {
2846                                                         starts[j] = starts[i]; lens[j] += lens[i];
2847                                                         lens[i] = 0;
2848                                                 } else if (starts[i] == starts[j]+lens[j]){
2849                                                         lens[j] += lens[i];
2850                                                         lens[i] = 0;
2851                                                 } else if (!k) {
2852                                                         if (starts[i] < starts[j]+lens[j]
2853                                                          && starts[j] < starts[i]+lens[i]) {
2854                                                                 starto = starts[i];
2855                                                                 if (starts[j] > starto)
2856                                                                         starto = starts[j];
2857                                                                 endo = starts[i]+lens[i];
2858                                                                 if (starts[j]+lens[j] < endo)
2859                                                                         endo = starts[j]+lens[j];
2860                                                                 printf(_("Partition %d overlaps with others in "
2861                                                                         "sectors %d-%d\n"), i+1, starto, endo);
2862                                                         }
2863                                                 }
2864                                         }
2865                         }
2866                 }
2867         }
2868         for (i = 0; i < 8; i++) {
2869                 if (lens[i])
2870                         array[i] = i;
2871                 else
2872                         array[i] = -1;
2873         }
2874         qsort(array,SIZE(array),sizeof(array[0]),
2875                 (int (*)(const void *,const void *)) verify_sun_cmp);
2876         if (array[0] == -1) {
2877                 printf(_("No partitions defined\n"));
2878                 return;
2879         }
2880         stop = cylinders * heads * sectors;
2881         if (starts[array[0]])
2882                 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2883         for (i = 0; i < 7 && array[i+1] != -1; i++) {
2884                 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2885         }
2886         start = starts[array[i]] + lens[array[i]];
2887         if (start < stop)
2888                 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2889 }
2890
2891 static void
2892 add_sun_partition(int n, int sys)
2893 {
2894         uint start, stop, stop2;
2895         uint starts[8], lens[8];
2896         int whole_disk = 0;
2897
2898         char mesg[256];
2899         int i, first, last;
2900
2901         if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2902                 printf(_("Partition %d is already defined.  Delete "
2903                         "it before re-adding it.\n"), n + 1);
2904                 return;
2905         }
2906
2907         fetch_sun(starts,lens,&start,&stop);
2908         if (stop <= start) {
2909                 if (n == 2)
2910                         whole_disk = 1;
2911                 else {
2912                         printf(_("Other partitions already cover the whole disk.\nDelete "
2913                                    "some/shrink them before retry.\n"));
2914                         return;
2915                 }
2916         }
2917         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2918         while (1) {
2919                 if (whole_disk)
2920                         first = read_int(0, 0, 0, 0, mesg);
2921                 else
2922                         first = read_int(scround(start), scround(stop)+1,
2923                                          scround(stop), 0, mesg);
2924                 if (display_in_cyl_units)
2925                         first *= units_per_sector;
2926                 else
2927                         /* Starting sector has to be properly aligned */
2928                         first = (first + heads * sectors - 1) / (heads * sectors);
2929                 if (n == 2 && first != 0)
2930                         printf("\
2931 It is highly recommended that the third partition covers the whole disk\n\
2932 and is of type `Whole disk'\n");
2933                 /* ewt asks to add: "don't start a partition at cyl 0"
2934                    However, edmundo@rano.demon.co.uk writes:
2935                    "In addition to having a Sun partition table, to be able to
2936                    boot from the disc, the first partition, /dev/sdX1, must
2937                    start at cylinder 0. This means that /dev/sdX1 contains
2938                    the partition table and the boot block, as these are the
2939                    first two sectors of the disc. Therefore you must be
2940                    careful what you use /dev/sdX1 for. In particular, you must
2941                    not use a partition starting at cylinder 0 for Linux swap,
2942                    as that would overwrite the partition table and the boot
2943                    block. You may, however, use such a partition for a UFS
2944                    or EXT2 file system, as these file systems leave the first
2945                    1024 bytes undisturbed. */
2946                 /* On the other hand, one should not use partitions
2947                    starting at block 0 in an md, or the label will
2948                    be trashed. */
2949                 for (i = 0; i < partitions; i++)
2950                         if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
2951                                 break;
2952                 if (i < partitions && !whole_disk) {
2953                         if (n == 2 && !first) {
2954                                 whole_disk = 1;
2955                                 break;
2956                         }
2957                         printf(_("Sector %d is already allocated\n"), first);
2958                 } else
2959                         break;
2960         }
2961         stop = cylinders * heads * sectors;
2962         stop2 = stop;
2963         for (i = 0; i < partitions; i++) {
2964                 if (starts[i] > first && starts[i] < stop)
2965                         stop = starts[i];
2966         }
2967         snprintf(mesg, sizeof(mesg),
2968                 _("Last %s or +size or +sizeM or +sizeK"),
2969                 str_units(SINGULAR));
2970         if (whole_disk)
2971                 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2972                                 0, mesg);
2973         else if (n == 2 && !first)
2974                 last = read_int(scround(first), scround(stop2), scround(stop2),
2975                                 scround(first), mesg);
2976         else
2977                 last = read_int(scround(first), scround(stop), scround(stop),
2978                                 scround(first), mesg);
2979         if (display_in_cyl_units)
2980                 last *= units_per_sector;
2981         if (n == 2 && !first) {
2982                 if (last >= stop2) {
2983                         whole_disk = 1;
2984                         last = stop2;
2985                 } else if (last > stop) {
2986                         printf(_("You haven't covered the whole disk with "
2987                                 "the 3rd partition, but your value\n"
2988                                 "%d %s covers some other partition. "
2989                                 "Your entry has been changed\n"
2990                                 "to %d %s\n"),
2991                                 scround(last), str_units(SINGULAR),
2992                                 scround(stop), str_units(SINGULAR));
2993                         last = stop;
2994                 }
2995         } else if (!whole_disk && last > stop)
2996                 last = stop;
2997
2998         if (whole_disk)
2999                 sys = WHOLE_DISK;
3000         set_sun_partition(n, first, last, sys);
3001 }
3002
3003 static void
3004 sun_delete_partition(int i)
3005 {
3006         unsigned int nsec;
3007
3008         if (i == 2
3009          && sunlabel->infos[i].id == WHOLE_DISK
3010          && !sunlabel->partitions[i].start_cylinder
3011          && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
3012                 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3013                         "consider leaving this\n"
3014                         "partition as Whole disk (5), starting at 0, with %u "
3015                         "sectors\n"), nsec);
3016         sunlabel->infos[i].id = 0;
3017         sunlabel->partitions[i].num_sectors = 0;
3018 }
3019
3020 static void
3021 sun_change_sysid(int i, int sys)
3022 {
3023         if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3024                 read_chars(
3025                         _("It is highly recommended that the partition at offset 0\n"
3026                         "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3027                         "there may destroy your partition table and bootblock.\n"
3028                         "Type YES if you're very sure you would like that partition\n"
3029                         "tagged with 82 (Linux swap): "));
3030                 if (strcmp (line_ptr, _("YES\n")))
3031                         return;
3032         }
3033         switch (sys) {
3034         case SUNOS_SWAP:
3035         case LINUX_SWAP:
3036                 /* swaps are not mountable by default */
3037                 sunlabel->infos[i].flags |= 0x01;
3038                 break;
3039         default:
3040                 /* assume other types are mountable;
3041                    user can change it anyway */
3042                 sunlabel->infos[i].flags &= ~0x01;
3043                 break;
3044         }
3045         sunlabel->infos[i].id = sys;
3046 }
3047
3048 static void
3049 sun_list_table(int xtra)
3050 {
3051         int i, w;
3052
3053         w = strlen(disk_device);
3054         if (xtra)
3055                 printf(
3056                 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3057                 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3058                 "%d extra sects/cyl, interleave %d:1\n"
3059                 "%s\n"
3060                 "Units = %s of %d * 512 bytes\n\n"),
3061                         disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3062                         cylinders, SUN_SSWAP16(sunlabel->nacyl),
3063                         SUN_SSWAP16(sunlabel->pcylcount),
3064                         SUN_SSWAP16(sunlabel->sparecyl),
3065                         SUN_SSWAP16(sunlabel->ilfact),
3066                         (char *)sunlabel,
3067                         str_units(PLURAL), units_per_sector);
3068         else
3069                 printf(
3070         _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3071         "Units = %s of %d * 512 bytes\n\n"),
3072                         disk_device, heads, sectors, cylinders,
3073                         str_units(PLURAL), units_per_sector);
3074
3075         printf(_("%*s Flag    Start       End    Blocks   Id  System\n"),
3076                 w + 1, _("Device"));
3077         for (i = 0 ; i < partitions; i++) {
3078                 if (sunlabel->partitions[i].num_sectors) {
3079                         uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3080                         uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
3081                         printf("%s %c%c %9ld %9ld %9ld%c  %2x  %s\n",
3082                                 partname(disk_device, i+1, w),                  /* device */
3083                                 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',  /* flags */
3084                                 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3085                                 (long) scround(start),                          /* start */
3086                                 (long) scround(start+len),                      /* end */
3087                                 (long) len / 2, len & 1 ? '+' : ' ',            /* odd flag on end */
3088                                 sunlabel->infos[i].id,                          /* type id */
3089                                 partition_type(sunlabel->infos[i].id));         /* type name */
3090                 }
3091         }
3092 }
3093
3094 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3095
3096 static void
3097 sun_set_alt_cyl(void)
3098 {
3099         sunlabel->nacyl =
3100                 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3101                                 _("Number of alternate cylinders")));
3102 }
3103
3104 static void
3105 sun_set_ncyl(int cyl)
3106 {
3107         sunlabel->ncyl = SUN_SSWAP16(cyl);
3108 }
3109
3110 static void
3111 sun_set_xcyl(void)
3112 {
3113         sunlabel->sparecyl =
3114                 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3115                                 _("Extra sectors per cylinder")));
3116 }
3117
3118 static void
3119 sun_set_ilfact(void)
3120 {
3121         sunlabel->ilfact =
3122                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3123                                 _("Interleave factor")));
3124 }
3125
3126 static void
3127 sun_set_rspeed(void)
3128 {
3129         sunlabel->rspeed =
3130                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3131                                 _("Rotation speed (rpm)")));
3132 }
3133
3134 static void
3135 sun_set_pcylcount(void)
3136 {
3137         sunlabel->pcylcount =
3138                 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3139                                 _("Number of physical cylinders")));
3140 }
3141 #endif /* CONFIG_FEATURE_FDISK_ADVANCED */
3142
3143 static void
3144 sun_write_table(void)
3145 {
3146         unsigned short *ush = (unsigned short *)sunlabel;
3147         unsigned short csum = 0;
3148
3149         while (ush < (unsigned short *)(&sunlabel->csum))
3150                 csum ^= *ush++;
3151         sunlabel->csum = csum;
3152         if (lseek(fd, 0, SEEK_SET) < 0)
3153                 fdisk_fatal(unable_to_seek);
3154         if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3155                 fdisk_fatal(unable_to_write);
3156 }
3157 #endif /* SUN_LABEL */
3158
3159 /* DOS partition types */
3160
3161 static const struct systypes i386_sys_types[] = {
3162         { "\x00" "Empty" },
3163         { "\x01" "FAT12" },
3164         { "\x04" "FAT16 <32M" },
3165         { "\x05" "Extended" },         /* DOS 3.3+ extended partition */
3166         { "\x06" "FAT16" },            /* DOS 16-bit >=32M */
3167         { "\x07" "HPFS/NTFS" },        /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3168         { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3169         { "\x0b" "Win95 FAT32" },
3170         { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3171         { "\x0e" "Win95 FAT16 (LBA)" },
3172         { "\x0f" "Win95 Ext'd (LBA)" },
3173         { "\x11" "Hidden FAT12" },
3174         { "\x12" "Compaq diagnostics" },
3175         { "\x14" "Hidden FAT16 <32M" },
3176         { "\x16" "Hidden FAT16" },
3177         { "\x17" "Hidden HPFS/NTFS" },
3178         { "\x1b" "Hidden Win95 FAT32" },
3179         { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3180         { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3181         { "\x3c" "PartitionMagic recovery" },
3182         { "\x41" "PPC PReP Boot" },
3183         { "\x42" "SFS" },
3184         { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3185         { "\x80" "Old Minix" },        /* Minix 1.4a and earlier */
3186         { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3187         { "\x82" "Linux swap" },       /* also Solaris */
3188         { "\x83" "Linux" },
3189         { "\x84" "OS/2 hidden C: drive" },
3190         { "\x85" "Linux extended" },
3191         { "\x86" "NTFS volume set" },
3192         { "\x87" "NTFS volume set" },
3193         { "\x8e" "Linux LVM" },
3194         { "\x9f" "BSD/OS" },           /* BSDI */
3195         { "\xa0" "IBM Thinkpad hibernation" },
3196         { "\xa5" "FreeBSD" },          /* various BSD flavours */
3197         { "\xa6" "OpenBSD" },
3198         { "\xa8" "Darwin UFS" },
3199         { "\xa9" "NetBSD" },
3200         { "\xab" "Darwin boot" },
3201         { "\xb7" "BSDI fs" },
3202         { "\xb8" "BSDI swap" },
3203         { "\xbe" "Solaris boot" },
3204         { "\xeb" "BeOS fs" },
3205         { "\xee" "EFI GPT" },          /* Intel EFI GUID Partition Table */
3206         { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3207         { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3208         { "\xf2" "DOS secondary" },    /* DOS 3.3+ secondary */
3209         { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3210                                                 autodetect using persistent
3211                                                 superblock */
3212 #ifdef CONFIG_WEIRD_PARTITION_TYPES
3213         { "\x02" "XENIX root" },
3214         { "\x03" "XENIX usr" },
3215         { "\x08" "AIX" },              /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3216         { "\x09" "AIX bootable" },     /* AIX data or Coherent */
3217         { "\x10" "OPUS" },
3218         { "\x18" "AST SmartSleep" },
3219         { "\x24" "NEC DOS" },
3220         { "\x39" "Plan 9" },
3221         { "\x40" "Venix 80286" },
3222         { "\x4d" "QNX4.x" },
3223         { "\x4e" "QNX4.x 2nd part" },
3224         { "\x4f" "QNX4.x 3rd part" },
3225         { "\x50" "OnTrack DM" },
3226         { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3227         { "\x52" "CP/M" },             /* CP/M or Microport SysV/AT */
3228         { "\x53" "OnTrack DM6 Aux3" },
3229         { "\x54" "OnTrackDM6" },
3230         { "\x55" "EZ-Drive" },
3231         { "\x56" "Golden Bow" },
3232         { "\x5c" "Priam Edisk" },
3233         { "\x61" "SpeedStor" },
3234         { "\x64" "Novell Netware 286" },
3235         { "\x65" "Novell Netware 386" },
3236         { "\x70" "DiskSecure Multi-Boot" },
3237         { "\x75" "PC/IX" },
3238         { "\x93" "Amoeba" },
3239         { "\x94" "Amoeba BBT" },       /* (bad block table) */
3240         { "\xa7" "NeXTSTEP" },
3241         { "\xbb" "Boot Wizard hidden" },
3242         { "\xc1" "DRDOS/sec (FAT-12)" },
3243         { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3244         { "\xc6" "DRDOS/sec (FAT-16)" },
3245         { "\xc7" "Syrinx" },
3246         { "\xda" "Non-FS data" },
3247         { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
3248                                         Concurrent DOS or CTOS */
3249         { "\xde" "Dell Utility" },     /* Dell PowerEdge Server utilities */
3250         { "\xdf" "BootIt" },           /* BootIt EMBRM */
3251         { "\xe1" "DOS access" },       /* DOS access or SpeedStor 12-bit FAT
3252                                         extended partition */
3253         { "\xe3" "DOS R/O" },          /* DOS R/O or SpeedStor */
3254         { "\xe4" "SpeedStor" },        /* SpeedStor 16-bit FAT extended
3255                                         partition < 1024 cyl. */
3256         { "\xf1" "SpeedStor" },
3257         { "\xf4" "SpeedStor" },        /* SpeedStor large partition */
3258         { "\xfe" "LANstep" },          /* SpeedStor >1024 cyl. or LANstep */
3259         { "\xff" "BBT" },              /* Xenix Bad Block Table */
3260 #endif
3261         { 0 }
3262 };
3263
3264
3265
3266 /* A valid partition table sector ends in 0x55 0xaa */
3267 static unsigned int
3268 part_table_flag(const char *b)
3269 {
3270         return ((uint) b[510]) + (((uint) b[511]) << 8);
3271 }
3272
3273
3274 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3275 static void
3276 write_part_table_flag(char *b)
3277 {
3278         b[510] = 0x55;
3279         b[511] = 0xaa;
3280 }
3281
3282 /* start_sect and nr_sects are stored little endian on all machines */
3283 /* moreover, they are not aligned correctly */
3284 static void
3285 store4_little_endian(unsigned char *cp, unsigned int val)
3286 {
3287         cp[0] = (val & 0xff);
3288         cp[1] = ((val >> 8) & 0xff);
3289         cp[2] = ((val >> 16) & 0xff);
3290         cp[3] = ((val >> 24) & 0xff);
3291 }
3292 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3293
3294 static unsigned int
3295 read4_little_endian(const unsigned char *cp)
3296 {
3297         return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3298                 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3299 }
3300
3301 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3302 static void
3303 set_start_sect(struct partition *p, unsigned int start_sect)
3304 {
3305         store4_little_endian(p->start4, start_sect);
3306 }
3307 #endif
3308
3309 static int32_t
3310 get_start_sect(const struct partition *p)
3311 {
3312         return read4_little_endian(p->start4);
3313 }
3314
3315 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3316 static void
3317 set_nr_sects(struct partition *p, int32_t nr_sects)
3318 {
3319         store4_little_endian(p->size4, nr_sects);
3320 }
3321 #endif
3322
3323 static int32_t
3324 get_nr_sects(const struct partition *p)
3325 {
3326         return read4_little_endian(p->size4);
3327 }
3328
3329 /* normally O_RDWR, -l option gives O_RDONLY */
3330 static int type_open = O_RDWR;
3331
3332
3333 static int ext_index;               /* the prime extended partition */
3334 static int listing;                    /* no aborts for fdisk -l */
3335 static int dos_compatible_flag = ~0;
3336 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3337 static int dos_changed;
3338 static int nowarn;            /* no warnings for fdisk -l/-s */
3339 #endif
3340
3341
3342
3343 static uint user_cylinders, user_heads, user_sectors;
3344 static uint pt_heads, pt_sectors;
3345 static uint kern_heads, kern_sectors;
3346
3347 static off_t extended_offset;            /* offset of link pointers */
3348
3349 static unsigned long long total_number_of_sectors;
3350
3351
3352 static jmp_buf listingbuf;
3353
3354 static void fdisk_fatal(enum failure why)
3355 {
3356         const char *message;
3357
3358         if (listing) {
3359                 close(fd);
3360                 longjmp(listingbuf, 1);
3361         }
3362
3363         switch (why) {
3364         case unable_to_open:
3365                 message = "Unable to open %s\n";
3366                 break;
3367         case unable_to_read:
3368                 message = "Unable to read %s\n";
3369                 break;
3370         case unable_to_seek:
3371                 message = "Unable to seek on %s\n";
3372                 break;
3373         case unable_to_write:
3374                 message = "Unable to write %s\n";
3375                 break;
3376         case ioctl_error:
3377                 message = "BLKGETSIZE ioctl failed on %s\n";
3378                 break;
3379         default:
3380                 message = "Fatal error\n";
3381         }
3382
3383         fputc('\n', stderr);
3384         fprintf(stderr, message, disk_device);
3385         exit(1);
3386 }
3387
3388 static void
3389 seek_sector(off_t secno)
3390 {
3391         off_t offset = secno * sector_size;
3392         if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
3393                 fdisk_fatal(unable_to_seek);
3394 }
3395
3396 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3397 static void
3398 write_sector(off_t secno, char *buf)
3399 {
3400         seek_sector(secno);
3401         if (write(fd, buf, sector_size) != sector_size)
3402                 fdisk_fatal(unable_to_write);
3403 }
3404 #endif
3405
3406 /* Allocate a buffer and read a partition table sector */
3407 static void
3408 read_pte(struct pte *pe, off_t offset)
3409 {
3410         pe->offset = offset;
3411         pe->sectorbuffer = (char *) xmalloc(sector_size);
3412         seek_sector(offset);
3413         if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3414                 fdisk_fatal(unable_to_read);
3415 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3416         pe->changed = 0;
3417 #endif
3418         pe->part_table = pe->ext_pointer = NULL;
3419 }
3420
3421 static unsigned int
3422 get_partition_start(const struct pte *pe)
3423 {
3424         return pe->offset + get_start_sect(pe->part_table);
3425 }
3426
3427 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3428 /*
3429  * Avoid warning about DOS partitions when no DOS partition was changed.
3430  * Here a heuristic "is probably dos partition".
3431  * We might also do the opposite and warn in all cases except
3432  * for "is probably nondos partition".
3433  */
3434 static int
3435 is_dos_partition(int t)
3436 {
3437         return (t == 1 || t == 4 || t == 6 ||
3438                 t == 0x0b || t == 0x0c || t == 0x0e ||
3439                 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3440                 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3441                 t == 0xc1 || t == 0xc4 || t == 0xc6);
3442 }
3443
3444 static void
3445 menu(void)
3446 {
3447 #ifdef CONFIG_FEATURE_SUN_LABEL
3448         if (label_sun == current_label_type) {
3449                 puts(_("Command action"));
3450                 puts(_("\ta\ttoggle a read only flag"));           /* sun */
3451                 puts(_("\tb\tedit bsd disklabel"));
3452                 puts(_("\tc\ttoggle the mountable flag"));         /* sun */
3453                 puts(_("\td\tdelete a partition"));
3454                 puts(_("\tl\tlist known partition types"));
3455                 puts(_("\tm\tprint this menu"));
3456                 puts(_("\tn\tadd a new partition"));
3457                 puts(_("\to\tcreate a new empty DOS partition table"));
3458                 puts(_("\tp\tprint the partition table"));
3459                 puts(_("\tq\tquit without saving changes"));
3460                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3461                 puts(_("\tt\tchange a partition's system id"));
3462                 puts(_("\tu\tchange display/entry units"));
3463                 puts(_("\tv\tverify the partition table"));
3464                 puts(_("\tw\twrite table to disk and exit"));
3465 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3466                 puts(_("\tx\textra functionality (experts only)"));
3467 #endif
3468         } else
3469 #endif
3470 #ifdef CONFIG_FEATURE_SGI_LABEL
3471         if (label_sgi == current_label_type) {
3472                 puts(_("Command action"));
3473                 puts(_("\ta\tselect bootable partition"));    /* sgi flavour */
3474                 puts(_("\tb\tedit bootfile entry"));          /* sgi */
3475                 puts(_("\tc\tselect sgi swap partition"));    /* sgi flavour */
3476                 puts(_("\td\tdelete a partition"));
3477                 puts(_("\tl\tlist known partition types"));
3478                 puts(_("\tm\tprint this menu"));
3479                 puts(_("\tn\tadd a new partition"));
3480                 puts(_("\to\tcreate a new empty DOS partition table"));
3481                 puts(_("\tp\tprint the partition table"));
3482                 puts(_("\tq\tquit without saving changes"));
3483                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3484                 puts(_("\tt\tchange a partition's system id"));
3485                 puts(_("\tu\tchange display/entry units"));
3486                 puts(_("\tv\tverify the partition table"));
3487                 puts(_("\tw\twrite table to disk and exit"));
3488         } else
3489 #endif
3490 #ifdef CONFIG_FEATURE_AIX_LABEL
3491         if (label_aix == current_label_type) {
3492                 puts(_("Command action"));
3493                 puts(_("\tm\tprint this menu"));
3494                 puts(_("\to\tcreate a new empty DOS partition table"));
3495                 puts(_("\tq\tquit without saving changes"));
3496                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3497         } else
3498 #endif
3499         {
3500                 puts(_("Command action"));
3501                 puts(_("\ta\ttoggle a bootable flag"));
3502                 puts(_("\tb\tedit bsd disklabel"));
3503                 puts(_("\tc\ttoggle the dos compatibility flag"));
3504                 puts(_("\td\tdelete a partition"));
3505                 puts(_("\tl\tlist known partition types"));
3506                 puts(_("\tm\tprint this menu"));
3507                 puts(_("\tn\tadd a new partition"));
3508                 puts(_("\to\tcreate a new empty DOS partition table"));
3509                 puts(_("\tp\tprint the partition table"));
3510                 puts(_("\tq\tquit without saving changes"));
3511                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3512                 puts(_("\tt\tchange a partition's system id"));
3513                 puts(_("\tu\tchange display/entry units"));
3514                 puts(_("\tv\tverify the partition table"));
3515                 puts(_("\tw\twrite table to disk and exit"));
3516 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3517                 puts(_("\tx\textra functionality (experts only)"));
3518 #endif
3519         }
3520 }
3521 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3522
3523
3524 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3525 static void
3526 xmenu(void)
3527 {
3528 #ifdef CONFIG_FEATURE_SUN_LABEL
3529         if (label_sun == current_label_type) {
3530         puts(_("Command action"));
3531         puts(_("\ta\tchange number of alternate cylinders"));      /*sun*/
3532         puts(_("\tc\tchange number of cylinders"));
3533         puts(_("\td\tprint the raw data in the partition table"));
3534         puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3535         puts(_("\th\tchange number of heads"));
3536         puts(_("\ti\tchange interleave factor"));                  /*sun*/
3537         puts(_("\to\tchange rotation speed (rpm)"));               /*sun*/
3538         puts(_("\tm\tprint this menu"));
3539         puts(_("\tp\tprint the partition table"));
3540         puts(_("\tq\tquit without saving changes"));
3541         puts(_("\tr\treturn to main menu"));
3542         puts(_("\ts\tchange number of sectors/track"));
3543         puts(_("\tv\tverify the partition table"));
3544         puts(_("\tw\twrite table to disk and exit"));
3545         puts(_("\ty\tchange number of physical cylinders"));       /*sun*/
3546         }  else
3547 #endif
3548 #ifdef CONFIG_FEATURE_SGI_LABEL
3549         if (label_sgi == current_label_type) {
3550                 puts(_("Command action"));
3551                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3552                 puts(_("\tc\tchange number of cylinders"));
3553                 puts(_("\td\tprint the raw data in the partition table"));
3554                 puts(_("\te\tlist extended partitions"));          /* !sun */
3555                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3556                 puts(_("\th\tchange number of heads"));
3557                 puts(_("\tm\tprint this menu"));
3558                 puts(_("\tp\tprint the partition table"));
3559                 puts(_("\tq\tquit without saving changes"));
3560                 puts(_("\tr\treturn to main menu"));
3561                 puts(_("\ts\tchange number of sectors/track"));
3562                 puts(_("\tv\tverify the partition table"));
3563                 puts(_("\tw\twrite table to disk and exit"));
3564         } else
3565 #endif
3566 #ifdef CONFIG_FEATURE_AIX_LABEL
3567         if (label_aix == current_label_type) {
3568                 puts(_("Command action"));
3569                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3570                 puts(_("\tc\tchange number of cylinders"));
3571                 puts(_("\td\tprint the raw data in the partition table"));
3572                 puts(_("\te\tlist extended partitions"));          /* !sun */
3573                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3574                 puts(_("\th\tchange number of heads"));
3575                 puts(_("\tm\tprint this menu"));
3576                 puts(_("\tp\tprint the partition table"));
3577                 puts(_("\tq\tquit without saving changes"));
3578                 puts(_("\tr\treturn to main menu"));
3579                 puts(_("\ts\tchange number of sectors/track"));
3580                 puts(_("\tv\tverify the partition table"));
3581                 puts(_("\tw\twrite table to disk and exit"));
3582         }  else
3583 #endif
3584         {
3585                 puts(_("Command action"));
3586                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3587                 puts(_("\tc\tchange number of cylinders"));
3588                 puts(_("\td\tprint the raw data in the partition table"));
3589                 puts(_("\te\tlist extended partitions"));          /* !sun */
3590                 puts(_("\tf\tfix partition order"));               /* !sun, !aix, !sgi */
3591 #ifdef CONFIG_FEATURE_SGI_LABEL
3592                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3593 #endif
3594                 puts(_("\th\tchange number of heads"));
3595                 puts(_("\tm\tprint this menu"));
3596                 puts(_("\tp\tprint the partition table"));
3597                 puts(_("\tq\tquit without saving changes"));
3598                 puts(_("\tr\treturn to main menu"));
3599                 puts(_("\ts\tchange number of sectors/track"));
3600                 puts(_("\tv\tverify the partition table"));
3601                 puts(_("\tw\twrite table to disk and exit"));
3602         }
3603 }
3604 #endif /* ADVANCED mode */
3605
3606 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3607 static const struct systypes *
3608 get_sys_types(void)
3609 {
3610         return (
3611 #ifdef CONFIG_FEATURE_SUN_LABEL
3612                 label_sun == current_label_type ? sun_sys_types :
3613 #endif
3614 #ifdef CONFIG_FEATURE_SGI_LABEL
3615                 label_sgi == current_label_type ? sgi_sys_types :
3616 #endif
3617                 i386_sys_types);
3618 }
3619 #else
3620 #define get_sys_types() i386_sys_types
3621 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3622
3623 static const char *partition_type(unsigned char type)
3624 {
3625         int i;
3626         const struct systypes *types = get_sys_types();
3627
3628         for (i = 0; types[i].name; i++)
3629                 if ((unsigned char )types[i].name[0] == type)
3630                         return types[i].name + 1;
3631
3632         return _("Unknown");
3633 }
3634
3635
3636 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3637 static int
3638 get_sysid(int i)
3639 {
3640         return (
3641 #ifdef CONFIG_FEATURE_SUN_LABEL
3642                 label_sun == current_label_type ? sunlabel->infos[i].id :
3643 #endif
3644 #ifdef CONFIG_FEATURE_SGI_LABEL
3645                 label_sgi == current_label_type ? sgi_get_sysid(i) :
3646 #endif
3647                 ptes[i].part_table->sys_ind);
3648 }
3649
3650 void list_types(const struct systypes *sys)
3651 {
3652         uint last[4], done = 0, next = 0, size;
3653         int i;
3654
3655         for (i = 0; sys[i].name; i++);
3656         size = i;
3657
3658         for (i = 3; i >= 0; i--)
3659                 last[3 - i] = done += (size + i - done) / (i + 1);
3660         i = done = 0;
3661
3662         do {
3663                 printf("%c%2x  %-15.15s", i ? ' ' : '\n',
3664                         (unsigned char)sys[next].name[0],
3665                         partition_type((unsigned char)sys[next].name[0]));
3666                 next = last[i++] + done;
3667                 if (i > 3 || next >= last[i]) {
3668                         i = 0;
3669                         next = ++done;
3670                 }
3671         } while (done < last[0]);
3672         putchar('\n');
3673 }
3674 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3675
3676 static int
3677 is_cleared_partition(const struct partition *p)
3678 {
3679         return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3680                  p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3681                  get_start_sect(p) || get_nr_sects(p));
3682 }
3683
3684 static void
3685 clear_partition(struct partition *p)
3686 {
3687         if (!p)
3688                 return;
3689         memset(p, 0, sizeof(struct partition));
3690 }
3691
3692 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3693 static void
3694 set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3695 {
3696         struct partition *p;
3697         off_t offset;
3698
3699         if (doext) {
3700                 p = ptes[i].ext_pointer;
3701                 offset = extended_offset;
3702         } else {
3703                 p = ptes[i].part_table;
3704                 offset = ptes[i].offset;
3705         }
3706         p->boot_ind = 0;
3707         p->sys_ind = sysid;
3708         set_start_sect(p, start - offset);
3709         set_nr_sects(p, stop - start + 1);
3710         if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3711                 start = heads*sectors*1024 - 1;
3712         set_hsc(p->head, p->sector, p->cyl, start);
3713         if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3714                 stop = heads*sectors*1024 - 1;
3715         set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3716         ptes[i].changed = 1;
3717 }
3718 #endif
3719
3720 static int
3721 test_c(const char **m, const char *mesg)
3722 {
3723         int val = 0;
3724         if (!*m)
3725                 fprintf(stderr, _("You must set"));
3726         else {
3727                 fprintf(stderr, " %s", *m);
3728                 val = 1;
3729         }
3730         *m = mesg;
3731         return val;
3732 }
3733
3734 static int
3735 warn_geometry(void)
3736 {
3737         const char *m = NULL;
3738         int prev = 0;
3739
3740         if (!heads)
3741                 prev = test_c(&m, _("heads"));
3742         if (!sectors)
3743                 prev = test_c(&m, _("sectors"));
3744         if (!cylinders)
3745                 prev = test_c(&m, _("cylinders"));
3746         if (!m)
3747                 return 0;
3748
3749         fprintf(stderr, "%s%s.\n"
3750 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3751                         "You can do this from the extra functions menu.\n"
3752 #endif
3753                 , prev ? _(" and ") : " ", m);
3754
3755         return 1;
3756 }
3757
3758 static void update_units(void)
3759 {
3760         int cyl_units = heads * sectors;
3761
3762         if (display_in_cyl_units && cyl_units)
3763                 units_per_sector = cyl_units;
3764         else
3765                 units_per_sector = 1;   /* in sectors */
3766 }
3767
3768 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3769 static void
3770 warn_cylinders(void)
3771 {
3772         if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
3773                 fprintf(stderr, _("\n"
3774 "The number of cylinders for this disk is set to %d.\n"
3775 "There is nothing wrong with that, but this is larger than 1024,\n"
3776 "and could in certain setups cause problems with:\n"
3777 "1) software that runs at boot time (e.g., old versions of LILO)\n"
3778 "2) booting and partitioning software from other OSs\n"
3779 "   (e.g., DOS FDISK, OS/2 FDISK)\n"),
3780                         cylinders);
3781 }
3782 #endif
3783
3784 static void
3785 read_extended(int ext)
3786 {
3787         int i;
3788         struct pte *pex;
3789         struct partition *p, *q;
3790
3791         ext_index = ext;
3792         pex = &ptes[ext];
3793         pex->ext_pointer = pex->part_table;
3794
3795         p = pex->part_table;
3796         if (!get_start_sect(p)) {
3797                 fprintf(stderr,
3798                         _("Bad offset in primary extended partition\n"));
3799                 return;
3800         }
3801
3802         while (IS_EXTENDED(p->sys_ind)) {
3803                 struct pte *pe = &ptes[partitions];
3804
3805                 if (partitions >= MAXIMUM_PARTS) {
3806                         /* This is not a Linux restriction, but
3807                            this program uses arrays of size MAXIMUM_PARTS.
3808                            Do not try to `improve' this test. */
3809                         struct pte *pre = &ptes[partitions-1];
3810 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3811                         fprintf(stderr,
3812                                 _("Warning: deleting partitions after %d\n"),
3813                                 partitions);
3814                         pre->changed = 1;
3815 #endif
3816                         clear_partition(pre->ext_pointer);
3817                         return;
3818                 }
3819
3820                 read_pte(pe, extended_offset + get_start_sect(p));
3821
3822                 if (!extended_offset)
3823                         extended_offset = get_start_sect(p);
3824
3825                 q = p = pt_offset(pe->sectorbuffer, 0);
3826                 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3827                         if (IS_EXTENDED(p->sys_ind)) {
3828                                 if (pe->ext_pointer)
3829                                         fprintf(stderr,
3830                                                 _("Warning: extra link "
3831                                                   "pointer in partition table"
3832                                                   " %d\n"), partitions + 1);
3833                                 else
3834                                         pe->ext_pointer = p;
3835                         } else if (p->sys_ind) {
3836                                 if (pe->part_table)
3837                                         fprintf(stderr,
3838                                                 _("Warning: ignoring extra "
3839                                                   "data in partition table"
3840                                                   " %d\n"), partitions + 1);
3841                                 else
3842                                         pe->part_table = p;
3843                         }
3844                 }
3845
3846                 /* very strange code here... */
3847                 if (!pe->part_table) {
3848                         if (q != pe->ext_pointer)
3849                                 pe->part_table = q;
3850                         else
3851                                 pe->part_table = q + 1;
3852                 }
3853                 if (!pe->ext_pointer) {
3854                         if (q != pe->part_table)
3855                                 pe->ext_pointer = q;
3856                         else
3857                                 pe->ext_pointer = q + 1;
3858                 }
3859
3860                 p = pe->ext_pointer;
3861                 partitions++;
3862         }
3863
3864 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3865         /* remove empty links */
3866  remove:
3867         for (i = 4; i < partitions; i++) {
3868                 struct pte *pe = &ptes[i];
3869
3870                 if (!get_nr_sects(pe->part_table) &&
3871                         (partitions > 5 || ptes[4].part_table->sys_ind)) {
3872                         printf("omitting empty partition (%d)\n", i+1);
3873                         delete_partition(i);
3874                         goto remove;    /* numbering changed */
3875                 }
3876         }
3877 #endif
3878 }
3879
3880 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3881 static void
3882 create_doslabel(void)
3883 {
3884         int i;
3885
3886         fprintf(stderr,
3887         _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3888           "until you decide to write them. After that, of course, the previous\n"
3889           "content won't be recoverable.\n\n"));
3890
3891         current_label_type = label_dos;
3892
3893 #ifdef CONFIG_FEATURE_OSF_LABEL
3894         possibly_osf_label = 0;
3895 #endif
3896         partitions = 4;
3897
3898         for (i = 510-64; i < 510; i++)
3899                 MBRbuffer[i] = 0;
3900         write_part_table_flag(MBRbuffer);
3901         extended_offset = 0;
3902         set_all_unchanged();
3903         set_changed(0);
3904         get_boot(create_empty_dos);
3905 }
3906 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3907
3908 static void
3909 get_sectorsize(void)
3910 {
3911         if (!user_set_sector_size) {
3912                 int arg;
3913                 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3914                         sector_size = arg;
3915                 if (sector_size != DEFAULT_SECTOR_SIZE)
3916                         printf(_("Note: sector size is %d (not %d)\n"),
3917                                    sector_size, DEFAULT_SECTOR_SIZE);
3918         }
3919 }
3920
3921 static void
3922 get_kernel_geometry(void)
3923 {
3924         struct hd_geometry geometry;
3925
3926         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3927                 kern_heads = geometry.heads;
3928                 kern_sectors = geometry.sectors;
3929                 /* never use geometry.cylinders - it is truncated */
3930         }
3931 }
3932
3933 static void
3934 get_partition_table_geometry(void)
3935 {
3936         const unsigned char *bufp = (const unsigned char *)MBRbuffer;
3937         struct partition *p;
3938         int i, h, s, hh, ss;
3939         int first = 1;
3940         int bad = 0;
3941
3942         if (!(valid_part_table_flag((char*)bufp)))
3943                 return;
3944
3945         hh = ss = 0;
3946         for (i = 0; i < 4; i++) {
3947                 p = pt_offset(bufp, i);
3948                 if (p->sys_ind != 0) {
3949                         h = p->end_head + 1;
3950                         s = (p->end_sector & 077);
3951                         if (first) {
3952                                 hh = h;
3953                                 ss = s;
3954                                 first = 0;
3955                         } else if (hh != h || ss != s)
3956                                 bad = 1;
3957                 }
3958         }
3959
3960         if (!first && !bad) {
3961                 pt_heads = hh;
3962                 pt_sectors = ss;
3963         }
3964 }
3965
3966 static void
3967 get_geometry(void)
3968 {
3969         int sec_fac;
3970         unsigned long long bytes;       /* really u64 */
3971
3972         get_sectorsize();
3973         sec_fac = sector_size / 512;
3974 #ifdef CONFIG_FEATURE_SUN_LABEL
3975         guess_device_type();
3976 #endif
3977         heads = cylinders = sectors = 0;
3978         kern_heads = kern_sectors = 0;
3979         pt_heads = pt_sectors = 0;
3980
3981         get_kernel_geometry();
3982         get_partition_table_geometry();
3983
3984         heads = user_heads ? user_heads :
3985                 pt_heads ? pt_heads :
3986                 kern_heads ? kern_heads : 255;
3987         sectors = user_sectors ? user_sectors :
3988                 pt_sectors ? pt_sectors :
3989                 kern_sectors ? kern_sectors : 63;
3990         if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3991                 /* got bytes */
3992         } else {
3993                 unsigned long longsectors;
3994
3995         if (ioctl(fd, BLKGETSIZE, &longsectors))
3996                 longsectors = 0;
3997                         bytes = ((unsigned long long) longsectors) << 9;
3998         }
3999
4000         total_number_of_sectors = (bytes >> 9);
4001
4002         sector_offset = 1;
4003         if (dos_compatible_flag)
4004                 sector_offset = sectors;
4005
4006         cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
4007         if (!cylinders)
4008                 cylinders = user_cylinders;
4009 }
4010
4011 /*
4012  * Read MBR.  Returns:
4013  *   -1: no 0xaa55 flag present (possibly entire disk BSD)
4014  *    0: found or created label
4015  *    1: I/O error
4016  */
4017 static int
4018 get_boot(enum action what)
4019 {
4020         int i;
4021
4022         partitions = 4;
4023
4024         for (i = 0; i < 4; i++) {
4025                 struct pte *pe = &ptes[i];
4026
4027                 pe->part_table = pt_offset(MBRbuffer, i);
4028                 pe->ext_pointer = NULL;
4029                 pe->offset = 0;
4030                 pe->sectorbuffer = MBRbuffer;
4031 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4032                 pe->changed = (what == create_empty_dos);
4033 #endif
4034         }
4035
4036 #ifdef CONFIG_FEATURE_SUN_LABEL
4037         if (what == create_empty_sun && check_sun_label())
4038                 return 0;
4039 #endif
4040
4041         memset(MBRbuffer, 0, 512);
4042
4043 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4044         if (what == create_empty_dos)
4045                 goto got_dos_table;             /* skip reading disk */
4046
4047         if ((fd = open(disk_device, type_open)) < 0) {
4048                 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4049                         if (what == try_only)
4050                                 return 1;
4051                         fdisk_fatal(unable_to_open);
4052                 } else
4053                         printf(_("You will not be able to write "
4054                                 "the partition table.\n"));
4055         }
4056
4057         if (512 != read(fd, MBRbuffer, 512)) {
4058                 if (what == try_only)
4059                         return 1;
4060                 fdisk_fatal(unable_to_read);
4061         }
4062 #else
4063         if ((fd = open(disk_device, O_RDONLY)) < 0)
4064                 return 1;
4065         if (512 != read(fd, MBRbuffer, 512))
4066                 return 1;
4067 #endif
4068
4069         get_geometry();
4070
4071         update_units();
4072
4073 #ifdef CONFIG_FEATURE_SUN_LABEL
4074         if (check_sun_label())
4075                 return 0;
4076 #endif
4077
4078 #ifdef CONFIG_FEATURE_SGI_LABEL
4079         if (check_sgi_label())
4080                 return 0;
4081 #endif
4082
4083 #ifdef CONFIG_FEATURE_AIX_LABEL
4084         if (check_aix_label())
4085                 return 0;
4086 #endif
4087
4088 #ifdef CONFIG_FEATURE_OSF_LABEL
4089         if (check_osf_label()) {
4090                 possibly_osf_label = 1;
4091                 if (!valid_part_table_flag(MBRbuffer)) {
4092                         current_label_type = label_osf;
4093                         return 0;
4094                 }
4095                 printf(_("This disk has both DOS and BSD magic.\n"
4096                          "Give the 'b' command to go to BSD mode.\n"));
4097         }
4098 #endif
4099
4100 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4101  got_dos_table:
4102 #endif
4103
4104         if (!valid_part_table_flag(MBRbuffer)) {
4105 #ifndef CONFIG_FEATURE_FDISK_WRITABLE
4106                 return -1;
4107 #else
4108                 switch (what) {
4109                 case fdisk:
4110                         fprintf(stderr,
4111                                 _("Device contains neither a valid DOS "
4112                                   "partition table, nor Sun, SGI or OSF "
4113                                   "disklabel\n"));
4114 #ifdef __sparc__
4115 #ifdef CONFIG_FEATURE_SUN_LABEL
4116                         create_sunlabel();
4117 #endif
4118 #else
4119                         create_doslabel();
4120 #endif
4121                         return 0;
4122                 case try_only:
4123                         return -1;
4124                 case create_empty_dos:
4125 #ifdef CONFIG_FEATURE_SUN_LABEL
4126                 case create_empty_sun:
4127 #endif
4128                         break;
4129                 default:
4130                         fprintf(stderr, _("Internal error\n"));
4131                         exit(1);
4132                 }
4133 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4134         }
4135
4136 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4137         warn_cylinders();
4138 #endif
4139         warn_geometry();
4140
4141         for (i = 0; i < 4; i++) {
4142                 struct pte *pe = &ptes[i];
4143
4144                 if (IS_EXTENDED(pe->part_table->sys_ind)) {
4145                         if (partitions != 4)
4146                                 fprintf(stderr, _("Ignoring extra extended "
4147                                         "partition %d\n"), i + 1);
4148                         else
4149                                 read_extended(i);
4150                 }
4151         }
4152
4153         for (i = 3; i < partitions; i++) {
4154                 struct pte *pe = &ptes[i];
4155
4156                 if (!valid_part_table_flag(pe->sectorbuffer)) {
4157                         fprintf(stderr,
4158                                 _("Warning: invalid flag 0x%04x of partition "
4159                                 "table %d will be corrected by w(rite)\n"),
4160                                 part_table_flag(pe->sectorbuffer), i + 1);
4161 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4162                         pe->changed = 1;
4163 #endif
4164                 }
4165         }
4166
4167         return 0;
4168 }
4169
4170 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4171 /*
4172  * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4173  * If the user hits Enter, DFLT is returned.
4174  * Answers like +10 are interpreted as offsets from BASE.
4175  *
4176  * There is no default if DFLT is not between LOW and HIGH.
4177  */
4178 static uint
4179 read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4180 {
4181         uint i;
4182         int default_ok = 1;
4183         static char *ms = NULL;
4184         static int mslen = 0;
4185
4186         if (!ms || strlen(mesg)+100 > mslen) {
4187                 mslen = strlen(mesg)+200;
4188                 ms = xrealloc(ms,mslen);
4189         }
4190
4191         if (dflt < low || dflt > high)
4192                 default_ok = 0;
4193
4194         if (default_ok)
4195                 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
4196                          mesg, low, high, dflt);
4197         else
4198                 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
4199
4200         while (1) {
4201                 int use_default = default_ok;
4202
4203                 /* ask question and read answer */
4204                 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4205                  && *line_ptr != '-' && *line_ptr != '+')
4206                         continue;
4207
4208                 if (*line_ptr == '+' || *line_ptr == '-') {
4209                         int minus = (*line_ptr == '-');
4210                         int absolute = 0;
4211
4212                         i = atoi(line_ptr+1);
4213
4214                         while (isdigit(*++line_ptr))
4215                                 use_default = 0;
4216
4217                         switch (*line_ptr) {
4218                         case 'c':
4219                         case 'C':
4220                                 if (!display_in_cyl_units)
4221                                         i *= heads * sectors;
4222                                 break;
4223                         case 'K':
4224                                 absolute = 1024;
4225                                 break;
4226                         case 'k':
4227                                 absolute = 1000;
4228                                 break;
4229                         case 'm':
4230                         case 'M':
4231                                 absolute = 1000000;
4232                                 break;
4233                         case 'g':
4234                         case 'G':
4235                                 absolute = 1000000000;
4236                                 break;
4237                         default:
4238                                 break;
4239                         }
4240                         if (absolute) {
4241                                 unsigned long long bytes;
4242                                 unsigned long unit;
4243
4244                                 bytes = (unsigned long long) i * absolute;
4245                                 unit = sector_size * units_per_sector;
4246                                 bytes += unit/2; /* round */
4247                                 bytes /= unit;
4248                                 i = bytes;
4249                         }
4250                         if (minus)
4251                                 i = -i;
4252                         i += base;
4253                 } else {
4254                         i = atoi(line_ptr);
4255                         while (isdigit(*line_ptr)) {
4256                                 line_ptr++;
4257                                 use_default = 0;
4258                         }
4259                 }
4260                 if (use_default)
4261                         printf(_("Using default value %u\n"), i = dflt);
4262                 if (i >= low && i <= high)
4263                         break;
4264                 else
4265                         printf(_("Value out of range.\n"));
4266         }
4267         return i;
4268 }
4269
4270 static int
4271 get_partition(int warn, int max)
4272 {
4273         struct pte *pe;
4274         int i;
4275
4276         i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4277         pe = &ptes[i];
4278
4279         if (warn) {
4280                 if (
4281                         (
4282                                 label_sun != current_label_type &&
4283                                 label_sgi != current_label_type &&
4284                                 !pe->part_table->sys_ind
4285                         )
4286 #ifdef CONFIG_FEATURE_SUN_LABEL
4287                         || (
4288                                 label_sun == current_label_type &&
4289                                 (
4290                                         !sunlabel->partitions[i].num_sectors
4291                                         || !sunlabel->infos[i].id
4292                                 )
4293                         )
4294 #endif
4295 #ifdef CONFIG_FEATURE_SGI_LABEL
4296                         || (
4297                                 label_sgi == current_label_type &&
4298                                  !sgi_get_num_sectors(i)
4299                         )
4300 #endif
4301                 ){
4302                         fprintf(stderr,
4303                                 _("Warning: partition %d has empty type\n"),
4304                                 i+1
4305                         );
4306                 }
4307         }
4308         return i;
4309 }
4310
4311 static int
4312 get_existing_partition(int warn, int max)
4313 {
4314         int pno = -1;
4315         int i;
4316
4317         for (i = 0; i < max; i++) {
4318                 struct pte *pe = &ptes[i];
4319                 struct partition *p = pe->part_table;
4320
4321                 if (p && !is_cleared_partition(p)) {
4322                         if (pno >= 0)
4323                                 goto not_unique;
4324                         pno = i;
4325                 }
4326         }
4327         if (pno >= 0) {
4328                 printf(_("Selected partition %d\n"), pno+1);
4329                 return pno;
4330         }
4331         printf(_("No partition is defined yet!\n"));
4332         return -1;
4333
4334  not_unique:
4335         return get_partition(warn, max);
4336 }
4337
4338 static int
4339 get_nonexisting_partition(int warn, int max)
4340 {
4341         int pno = -1;
4342         int i;
4343
4344         for (i = 0; i < max; i++) {
4345                 struct pte *pe = &ptes[i];
4346                 struct partition *p = pe->part_table;
4347
4348                 if (p && is_cleared_partition(p)) {
4349                         if (pno >= 0)
4350                                 goto not_unique;
4351                         pno = i;
4352                 }
4353         }
4354         if (pno >= 0) {
4355                 printf(_("Selected partition %d\n"), pno+1);
4356                 return pno;
4357         }
4358         printf(_("All primary partitions have been defined already!\n"));
4359         return -1;
4360
4361  not_unique:
4362         return get_partition(warn, max);
4363 }
4364
4365
4366 void change_units(void)
4367 {
4368         display_in_cyl_units = !display_in_cyl_units;
4369         update_units();
4370         printf(_("Changing display/entry units to %s\n"),
4371                 str_units(PLURAL));
4372 }
4373
4374 static void
4375 toggle_active(int i)
4376 {
4377         struct pte *pe = &ptes[i];
4378         struct partition *p = pe->part_table;
4379
4380         if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
4381                 fprintf(stderr,
4382                         _("WARNING: Partition %d is an extended partition\n"),
4383                         i + 1);
4384         p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4385         pe->changed = 1;
4386 }
4387
4388 static void
4389 toggle_dos_compatibility_flag(void)
4390 {
4391         dos_compatible_flag = ~dos_compatible_flag;
4392         if (dos_compatible_flag) {
4393                 sector_offset = sectors;
4394                 printf(_("DOS Compatibility flag is set\n"));
4395         }
4396         else {
4397                 sector_offset = 1;
4398                 printf(_("DOS Compatibility flag is not set\n"));
4399         }
4400 }
4401
4402 static void
4403 delete_partition(int i)
4404 {
4405         struct pte *pe = &ptes[i];
4406         struct partition *p = pe->part_table;
4407         struct partition *q = pe->ext_pointer;
4408
4409 /* Note that for the fifth partition (i == 4) we don't actually
4410  * decrement partitions.
4411  */
4412
4413         if (warn_geometry())
4414                 return;         /* C/H/S not set */
4415         pe->changed = 1;
4416
4417 #ifdef CONFIG_FEATURE_SUN_LABEL
4418         if (label_sun == current_label_type) {
4419                 sun_delete_partition(i);
4420                 return;
4421         }
4422 #endif
4423 #ifdef CONFIG_FEATURE_SGI_LABEL
4424         if (label_sgi == current_label_type) {
4425                 sgi_delete_partition(i);
4426                 return;
4427         }
4428 #endif
4429
4430         if (i < 4) {
4431                 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
4432                         partitions = 4;
4433                         ptes[ext_index].ext_pointer = NULL;
4434                         extended_offset = 0;
4435                 }
4436                 clear_partition(p);
4437                 return;
4438         }
4439
4440         if (!q->sys_ind && i > 4) {
4441                 /* the last one in the chain - just delete */
4442                 --partitions;
4443                 --i;
4444                 clear_partition(ptes[i].ext_pointer);
4445                 ptes[i].changed = 1;
4446         } else {
4447                 /* not the last one - further ones will be moved down */
4448                 if (i > 4) {
4449                         /* delete this link in the chain */
4450                         p = ptes[i-1].ext_pointer;
4451                         *p = *q;
4452                         set_start_sect(p, get_start_sect(q));
4453                         set_nr_sects(p, get_nr_sects(q));
4454                         ptes[i-1].changed = 1;
4455                 } else if (partitions > 5) {    /* 5 will be moved to 4 */
4456                         /* the first logical in a longer chain */
4457                         pe = &ptes[5];
4458
4459                         if (pe->part_table) /* prevent SEGFAULT */
4460                                 set_start_sect(pe->part_table,
4461                                                    get_partition_start(pe) -
4462                                                    extended_offset);
4463                         pe->offset = extended_offset;
4464                         pe->changed = 1;
4465                 }
4466
4467                 if (partitions > 5) {
4468                         partitions--;
4469                         while (i < partitions) {
4470                                 ptes[i] = ptes[i+1];
4471                                 i++;
4472                         }
4473                 } else
4474                         /* the only logical: clear only */
4475                         clear_partition(ptes[i].part_table);
4476         }
4477 }
4478
4479 static void
4480 change_sysid(void)
4481 {
4482         int i, sys, origsys;
4483         struct partition *p;
4484
4485 #ifdef CONFIG_FEATURE_SGI_LABEL
4486         /* If sgi_label then don't use get_existing_partition,
4487            let the user select a partition, since get_existing_partition()
4488            only works for Linux like partition tables. */
4489         if (label_sgi != current_label_type) {
4490                 i = get_existing_partition(0, partitions);
4491         } else {
4492                 i = get_partition(0, partitions);
4493         }
4494 #else
4495         i = get_existing_partition(0, partitions);
4496 #endif
4497         if (i == -1)
4498                 return;
4499         p = ptes[i].part_table;
4500         origsys = sys = get_sysid(i);
4501
4502         /* if changing types T to 0 is allowed, then
4503            the reverse change must be allowed, too */
4504         if (!sys && label_sgi != current_label_type &&
4505                 label_sun != current_label_type && !get_nr_sects(p))
4506         {
4507                 printf(_("Partition %d does not exist yet!\n"), i + 1);
4508         } else while (1) {
4509                 sys = read_hex (get_sys_types());
4510
4511                 if (!sys && label_sgi != current_label_type &&
4512                         label_sun != current_label_type)
4513                 {
4514                         printf(_("Type 0 means free space to many systems\n"
4515                                    "(but not to Linux). Having partitions of\n"
4516                                    "type 0 is probably unwise. You can delete\n"
4517                                    "a partition using the `d' command.\n"));
4518                         /* break; */
4519                 }
4520
4521                 if (label_sun != current_label_type && label_sgi != current_label_type) {
4522                         if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
4523                                 printf(_("You cannot change a partition into"
4524                                            " an extended one or vice versa\n"
4525                                            "Delete it first.\n"));
4526                                 break;
4527                         }
4528                 }
4529
4530                 if (sys < 256) {
4531 #ifdef CONFIG_FEATURE_SUN_LABEL
4532                         if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
4533                                 printf(_("Consider leaving partition 3 "
4534                                            "as Whole disk (5),\n"
4535                                            "as SunOS/Solaris expects it and "
4536                                            "even Linux likes it.\n\n"));
4537 #endif
4538 #ifdef CONFIG_FEATURE_SGI_LABEL
4539                         if (label_sgi == current_label_type &&
4540                                 (
4541                                         (i == 10 && sys != ENTIRE_DISK) ||
4542                                         (i == 8 && sys != 0)
4543                                 )
4544                         ){
4545                                 printf(_("Consider leaving partition 9 "
4546                                            "as volume header (0),\nand "
4547                                            "partition 11 as entire volume (6)"
4548                                            "as IRIX expects it.\n\n"));
4549                         }
4550 #endif
4551                         if (sys == origsys)
4552                                 break;
4553 #ifdef CONFIG_FEATURE_SUN_LABEL
4554                         if (label_sun == current_label_type) {
4555                                 sun_change_sysid(i, sys);
4556                         } else
4557 #endif
4558 #ifdef CONFIG_FEATURE_SGI_LABEL
4559                         if (label_sgi == current_label_type) {
4560                                 sgi_change_sysid(i, sys);
4561                         } else
4562 #endif
4563                                 p->sys_ind = sys;
4564
4565                         printf(_("Changed system type of partition %d "
4566                                 "to %x (%s)\n"), i + 1, sys,
4567                                 partition_type(sys));
4568                         ptes[i].changed = 1;
4569                         if (is_dos_partition(origsys) ||
4570                                 is_dos_partition(sys))
4571                                 dos_changed = 1;
4572                         break;
4573                 }
4574         }
4575 }
4576 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4577
4578
4579 /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4580  * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4581  * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4582  * Lubkin Oct.  1991). */
4583
4584 static void
4585 long2chs(ulong ls, uint *c, uint *h, uint *s)
4586 {
4587         int spc = heads * sectors;
4588
4589         *c = ls / spc;
4590         ls = ls % spc;
4591         *h = ls / sectors;
4592         *s = ls % sectors + 1;  /* sectors count from 1 */
4593 }
4594
4595 static void
4596 check_consistency(const struct partition *p, int partition)
4597 {
4598         uint pbc, pbh, pbs;          /* physical beginning c, h, s */
4599         uint pec, peh, pes;          /* physical ending c, h, s */
4600         uint lbc, lbh, lbs;          /* logical beginning c, h, s */
4601         uint lec, leh, les;          /* logical ending c, h, s */
4602
4603         if (!heads || !sectors || (partition >= 4))
4604                 return;         /* do not check extended partitions */
4605
4606 /* physical beginning c, h, s */
4607         pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4608         pbh = p->head;
4609         pbs = p->sector & 0x3f;
4610
4611 /* physical ending c, h, s */
4612         pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4613         peh = p->end_head;
4614         pes = p->end_sector & 0x3f;
4615
4616 /* compute logical beginning (c, h, s) */
4617         long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4618
4619 /* compute logical ending (c, h, s) */
4620         long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4621
4622 /* Same physical / logical beginning? */
4623         if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4624                 printf(_("Partition %d has different physical/logical "
4625                         "beginnings (non-Linux?):\n"), partition + 1);
4626                 printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
4627                 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4628         }
4629
4630 /* Same physical / logical ending? */
4631         if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4632                 printf(_("Partition %d has different physical/logical "
4633                         "endings:\n"), partition + 1);
4634                 printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
4635                 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4636         }
4637
4638 /* Ending on cylinder boundary? */
4639         if (peh != (heads - 1) || pes != sectors) {
4640                 printf(_("Partition %i does not end on cylinder boundary.\n"),
4641                         partition + 1);
4642         }
4643 }
4644
4645 static void
4646 list_disk_geometry(void)
4647 {
4648         long long bytes = (total_number_of_sectors << 9);
4649         long megabytes = bytes/1000000;
4650
4651         if (megabytes < 10000)
4652                 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4653                            disk_device, megabytes, bytes);
4654         else
4655                 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4656                            disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4657         printf(_("%d heads, %d sectors/track, %d cylinders"),
4658                    heads, sectors, cylinders);
4659         if (units_per_sector == 1)
4660                 printf(_(", total %llu sectors"),
4661                            total_number_of_sectors / (sector_size/512));
4662         printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
4663                    str_units(PLURAL),
4664                    units_per_sector, sector_size, units_per_sector * sector_size);
4665 }
4666
4667 /*
4668  * Check whether partition entries are ordered by their starting positions.
4669  * Return 0 if OK. Return i if partition i should have been earlier.
4670  * Two separate checks: primary and logical partitions.
4671  */
4672 static int
4673 wrong_p_order(int *prev)
4674 {
4675         const struct pte *pe;
4676         const struct partition *p;
4677         off_t last_p_start_pos = 0, p_start_pos;
4678         int i, last_i = 0;
4679
4680         for (i = 0 ; i < partitions; i++) {
4681                 if (i == 4) {
4682                         last_i = 4;
4683                         last_p_start_pos = 0;
4684                 }
4685                 pe = &ptes[i];
4686                 if ((p = pe->part_table)->sys_ind) {
4687                         p_start_pos = get_partition_start(pe);
4688
4689                         if (last_p_start_pos > p_start_pos) {
4690                                 if (prev)
4691                                         *prev = last_i;
4692                                 return i;
4693                         }
4694
4695                         last_p_start_pos = p_start_pos;
4696                         last_i = i;
4697                 }
4698         }
4699         return 0;
4700 }
4701
4702 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
4703 /*
4704  * Fix the chain of logicals.
4705  * extended_offset is unchanged, the set of sectors used is unchanged
4706  * The chain is sorted so that sectors increase, and so that
4707  * starting sectors increase.
4708  *
4709  * After this it may still be that cfdisk doesnt like the table.
4710  * (This is because cfdisk considers expanded parts, from link to
4711  * end of partition, and these may still overlap.)
4712  * Now
4713  *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4714  * may help.
4715  */
4716 static void
4717 fix_chain_of_logicals(void)
4718 {
4719         int j, oj, ojj, sj, sjj;
4720         struct partition *pj,*pjj,tmp;
4721
4722         /* Stage 1: sort sectors but leave sector of part 4 */
4723         /* (Its sector is the global extended_offset.) */
4724  stage1:
4725         for (j = 5; j < partitions-1; j++) {
4726                 oj = ptes[j].offset;
4727                 ojj = ptes[j+1].offset;
4728                 if (oj > ojj) {
4729                         ptes[j].offset = ojj;
4730                         ptes[j+1].offset = oj;
4731                         pj = ptes[j].part_table;
4732                         set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4733                         pjj = ptes[j+1].part_table;
4734                         set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4735                         set_start_sect(ptes[j-1].ext_pointer,
4736                                            ojj-extended_offset);
4737                         set_start_sect(ptes[j].ext_pointer,
4738                                            oj-extended_offset);
4739                         goto stage1;
4740                 }
4741         }
4742
4743         /* Stage 2: sort starting sectors */
4744  stage2:
4745         for (j = 4; j < partitions-1; j++) {
4746                 pj = ptes[j].part_table;
4747                 pjj = ptes[j+1].part_table;
4748                 sj = get_start_sect(pj);
4749                 sjj = get_start_sect(pjj);
4750                 oj = ptes[j].offset;
4751                 ojj = ptes[j+1].offset;
4752                 if (oj+sj > ojj+sjj) {
4753                         tmp = *pj;
4754                         *pj = *pjj;
4755                         *pjj = tmp;
4756                         set_start_sect(pj, ojj+sjj-oj);
4757                         set_start_sect(pjj, oj+sj-ojj);
4758                         goto stage2;
4759                 }
4760         }
4761
4762         /* Probably something was changed */
4763         for (j = 4; j < partitions; j++)
4764                 ptes[j].changed = 1;
4765 }
4766
4767
4768 static void
4769 fix_partition_table_order(void)
4770 {
4771         struct pte *pei, *pek;
4772         int i,k;
4773
4774         if (!wrong_p_order(NULL)) {
4775                 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4776                 return;
4777         }
4778
4779         while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4780                 /* partition i should have come earlier, move it */
4781                 /* We have to move data in the MBR */
4782                 struct partition *pi, *pk, *pe, pbuf;
4783                 pei = &ptes[i];
4784                 pek = &ptes[k];
4785
4786                 pe = pei->ext_pointer;
4787                 pei->ext_pointer = pek->ext_pointer;
4788                 pek->ext_pointer = pe;
4789
4790                 pi = pei->part_table;
4791                 pk = pek->part_table;
4792
4793                 memmove(&pbuf, pi, sizeof(struct partition));
4794                 memmove(pi, pk, sizeof(struct partition));
4795                 memmove(pk, &pbuf, sizeof(struct partition));
4796
4797                 pei->changed = pek->changed = 1;
4798         }
4799
4800         if (i)
4801                 fix_chain_of_logicals();
4802
4803         printf("Done.\n");
4804
4805 }
4806 #endif
4807
4808 static void
4809 list_table(int xtra)
4810 {
4811         const struct partition *p;
4812         int i, w;
4813
4814 #ifdef CONFIG_FEATURE_SUN_LABEL
4815         if (label_sun == current_label_type) {
4816                 sun_list_table(xtra);
4817                 return;
4818         }
4819 #endif
4820
4821 #ifdef CONFIG_FEATURE_SGI_LABEL
4822         if (label_sgi == current_label_type) {
4823                 sgi_list_table(xtra);
4824                 return;
4825         }
4826 #endif
4827
4828         list_disk_geometry();
4829
4830 #ifdef CONFIG_FEATURE_OSF_LABEL
4831         if (label_osf == current_label_type) {
4832                 xbsd_print_disklabel(xtra);
4833                 return;
4834         }
4835 #endif
4836
4837         /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4838            but if the device name ends in a digit, say /dev/foo1,
4839            then the partition is called /dev/foo1p3. */
4840         w = strlen(disk_device);
4841         if (w && isdigit(disk_device[w-1]))
4842                 w++;
4843         if (w < 5)
4844                 w = 5;
4845
4846         printf(_("%*s Boot    Start       End    Blocks   Id  System\n"),
4847                    w+1, _("Device"));
4848
4849         for (i = 0; i < partitions; i++) {
4850                 const struct pte *pe = &ptes[i];
4851
4852                 p = pe->part_table;
4853                 if (p && !is_cleared_partition(p)) {
4854                         off_t psects = get_nr_sects(p);
4855                         off_t pblocks = psects;
4856                         unsigned int podd = 0;
4857
4858                         if (sector_size < 1024) {
4859                                 pblocks /= (1024 / sector_size);
4860                                 podd = psects % (1024 / sector_size);
4861                         }
4862                         if (sector_size > 1024)
4863                                 pblocks *= (sector_size / 1024);
4864                         printf(
4865                                 "%s  %c %11llu %11llu %11llu%c  %2x  %s\n",
4866                         partname(disk_device, i+1, w+2),
4867 /* boot flag */         !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4868                         ? '*' : '?',
4869 /* start */             (unsigned long long) cround(get_partition_start(pe)),
4870 /* end */               (unsigned long long) cround(get_partition_start(pe) + psects
4871                                 - (psects ? 1 : 0)),
4872 /* odd flag on end */   (unsigned long long) pblocks, podd ? '+' : ' ',
4873 /* type id */           p->sys_ind,
4874 /* type name */         partition_type(p->sys_ind));
4875                         check_consistency(p, i);
4876                 }
4877         }
4878
4879         /* Is partition table in disk order? It need not be, but... */
4880         /* partition table entries are not checked for correct order if this
4881            is a sgi, sun or aix labeled disk... */
4882         if (label_dos == current_label_type && wrong_p_order(NULL)) {
4883                 /* FIXME */
4884                 printf(_("\nPartition table entries are not in disk order\n"));
4885         }
4886 }
4887
4888 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
4889 static void
4890 x_list_table(int extend)
4891 {
4892         const struct pte *pe;
4893         const struct partition *p;
4894         int i;
4895
4896         printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4897                 disk_device, heads, sectors, cylinders);
4898         printf(_("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl    Start     Size ID\n"));
4899         for (i = 0 ; i < partitions; i++) {
4900                 pe = &ptes[i];
4901                 p = (extend ? pe->ext_pointer : pe->part_table);
4902                 if (p != NULL) {
4903                         printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
4904                                 i + 1, p->boot_ind, p->head,
4905                                 sector(p->sector),
4906                                 cylinder(p->sector, p->cyl), p->end_head,
4907                                 sector(p->end_sector),
4908                                 cylinder(p->end_sector, p->end_cyl),
4909                                 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4910                         if (p->sys_ind)
4911                                 check_consistency(p, i);
4912                 }
4913         }
4914 }
4915 #endif
4916
4917 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4918 static void
4919 fill_bounds(off_t *first, off_t *last)
4920 {
4921         int i;
4922         const struct pte *pe = &ptes[0];
4923         const struct partition *p;
4924
4925         for (i = 0; i < partitions; pe++,i++) {
4926                 p = pe->part_table;
4927                 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
4928                         first[i] = 0xffffffff;
4929                         last[i] = 0;
4930                 } else {
4931                         first[i] = get_partition_start(pe);
4932                         last[i] = first[i] + get_nr_sects(p) - 1;
4933                 }
4934         }
4935 }
4936
4937 static void
4938 check(int n, uint h, uint s, uint c, off_t start)
4939 {
4940         off_t total, real_s, real_c;
4941
4942         real_s = sector(s) - 1;
4943         real_c = cylinder(s, c);
4944         total = (real_c * sectors + real_s) * heads + h;
4945         if (!total)
4946                 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4947         if (h >= heads)
4948                 fprintf(stderr,
4949                         _("Partition %d: head %d greater than maximum %d\n"),
4950                         n, h + 1, heads);
4951         if (real_s >= sectors)
4952                 fprintf(stderr, _("Partition %d: sector %d greater than "
4953                         "maximum %d\n"), n, s, sectors);
4954         if (real_c >= cylinders)
4955                 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4956                         "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
4957         if (cylinders <= 1024 && start != total)
4958                 fprintf(stderr,
4959                         _("Partition %d: previous sectors %llu disagrees with "
4960                         "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
4961 }
4962
4963 static void
4964 verify(void)
4965 {
4966         int i, j;
4967         uint total = 1;
4968         off_t first[partitions], last[partitions];
4969         struct partition *p;
4970
4971         if (warn_geometry())
4972                 return;
4973
4974 #ifdef CONFIG_FEATURE_SUN_LABEL
4975         if (label_sun == current_label_type) {
4976                 verify_sun();
4977                 return;
4978         }
4979 #endif
4980 #ifdef CONFIG_FEATURE_SGI_LABEL
4981         if (label_sgi == current_label_type) {
4982                 verify_sgi(1);
4983                 return;
4984         }
4985 #endif
4986
4987         fill_bounds(first, last);
4988         for (i = 0; i < partitions; i++) {
4989                 struct pte *pe = &ptes[i];
4990
4991                 p = pe->part_table;
4992                 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
4993                         check_consistency(p, i);
4994                         if (get_partition_start(pe) < first[i])
4995                                 printf(_("Warning: bad start-of-data in "
4996                                         "partition %d\n"), i + 1);
4997                         check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4998                                 last[i]);
4999                         total += last[i] + 1 - first[i];
5000                         for (j = 0; j < i; j++)
5001                         if ((first[i] >= first[j] && first[i] <= last[j])
5002                          || ((last[i] <= last[j] && last[i] >= first[j]))) {
5003                                 printf(_("Warning: partition %d overlaps "
5004                                         "partition %d.\n"), j + 1, i + 1);
5005                                 total += first[i] >= first[j] ?
5006                                         first[i] : first[j];
5007                                 total -= last[i] <= last[j] ?
5008                                         last[i] : last[j];
5009                         }
5010                 }
5011         }
5012
5013         if (extended_offset) {
5014                 struct pte *pex = &ptes[ext_index];
5015                 off_t e_last = get_start_sect(pex->part_table) +
5016                         get_nr_sects(pex->part_table) - 1;
5017
5018                 for (i = 4; i < partitions; i++) {
5019                         total++;
5020                         p = ptes[i].part_table;
5021                         if (!p->sys_ind) {
5022                                 if (i != 4 || i + 1 < partitions)
5023                                         printf(_("Warning: partition %d "
5024                                                 "is empty\n"), i + 1);
5025                         }
5026                         else if (first[i] < extended_offset ||
5027                                         last[i] > e_last)
5028                                 printf(_("Logical partition %d not entirely in "
5029                                         "partition %d\n"), i + 1, ext_index + 1);
5030                 }
5031         }
5032
5033         if (total > heads * sectors * cylinders)
5034                 printf(_("Total allocated sectors %d greater than the maximum "
5035                         "%d\n"), total, heads * sectors * cylinders);
5036         else if ((total = heads * sectors * cylinders - total) != 0)
5037                 printf(_("%d unallocated sectors\n"), total);
5038 }
5039
5040 static void
5041 add_partition(int n, int sys)
5042 {
5043         char mesg[256];         /* 48 does not suffice in Japanese */
5044         int i, num_read = 0;
5045         struct partition *p = ptes[n].part_table;
5046         struct partition *q = ptes[ext_index].part_table;
5047         long long llimit;
5048         off_t start, stop = 0, limit, temp,
5049                 first[partitions], last[partitions];
5050
5051         if (p && p->sys_ind) {
5052                 printf(_("Partition %d is already defined.  Delete "
5053                          "it before re-adding it.\n"), n + 1);
5054                 return;
5055         }
5056         fill_bounds(first, last);
5057         if (n < 4) {
5058                 start = sector_offset;
5059                 if (display_in_cyl_units || !total_number_of_sectors)
5060                         llimit = heads * sectors * cylinders - 1;
5061                 else
5062                         llimit = total_number_of_sectors - 1;
5063                 limit = llimit;
5064                 if (limit != llimit)
5065                         limit = 0x7fffffff;
5066                 if (extended_offset) {
5067                         first[ext_index] = extended_offset;
5068                         last[ext_index] = get_start_sect(q) +
5069                                 get_nr_sects(q) - 1;
5070                 }
5071         } else {
5072                 start = extended_offset + sector_offset;
5073                 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5074         }
5075         if (display_in_cyl_units)
5076                 for (i = 0; i < partitions; i++)
5077                         first[i] = (cround(first[i]) - 1) * units_per_sector;
5078
5079         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5080         do {
5081                 temp = start;
5082                 for (i = 0; i < partitions; i++) {
5083                         int lastplusoff;
5084
5085                         if (start == ptes[i].offset)
5086                                 start += sector_offset;
5087                         lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
5088                         if (start >= first[i] && start <= lastplusoff)
5089                                 start = lastplusoff + 1;
5090                 }
5091                 if (start > limit)
5092                         break;
5093                 if (start >= temp+units_per_sector && num_read) {
5094                         printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
5095                         temp = start;
5096                         num_read = 0;
5097                 }
5098                 if (!num_read && start == temp) {
5099                         off_t saved_start;
5100
5101                         saved_start = start;
5102                         start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5103                                          0, mesg);
5104                         if (display_in_cyl_units) {
5105                                 start = (start - 1) * units_per_sector;
5106                                 if (start < saved_start) start = saved_start;
5107                         }
5108                         num_read = 1;
5109                 }
5110         } while (start != temp || !num_read);
5111         if (n > 4) {                    /* NOT for fifth partition */
5112                 struct pte *pe = &ptes[n];
5113
5114                 pe->offset = start - sector_offset;
5115                 if (pe->offset == extended_offset) { /* must be corrected */
5116                         pe->offset++;
5117                         if (sector_offset == 1)
5118                                 start++;
5119                 }
5120         }
5121
5122         for (i = 0; i < partitions; i++) {
5123                 struct pte *pe = &ptes[i];
5124
5125                 if (start < pe->offset && limit >= pe->offset)
5126                         limit = pe->offset - 1;
5127                 if (start < first[i] && limit >= first[i])
5128                         limit = first[i] - 1;
5129         }
5130         if (start > limit) {
5131                 printf(_("No free sectors available\n"));
5132                 if (n > 4)
5133                         partitions--;
5134                 return;
5135         }
5136         if (cround(start) == cround(limit)) {
5137                 stop = limit;
5138         } else {
5139                 snprintf(mesg, sizeof(mesg),
5140                          _("Last %s or +size or +sizeM or +sizeK"),
5141                          str_units(SINGULAR));
5142                 stop = read_int(cround(start), cround(limit), cround(limit),
5143                                 cround(start), mesg);
5144                 if (display_in_cyl_units) {
5145                         stop = stop * units_per_sector - 1;
5146                         if (stop >limit)
5147                                 stop = limit;
5148                 }
5149         }
5150
5151         set_partition(n, 0, start, stop, sys);
5152         if (n > 4)
5153                 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5154
5155         if (IS_EXTENDED(sys)) {
5156                 struct pte *pe4 = &ptes[4];
5157                 struct pte *pen = &ptes[n];
5158
5159                 ext_index = n;
5160                 pen->ext_pointer = p;
5161                 pe4->offset = extended_offset = start;
5162                 pe4->sectorbuffer = xzalloc(sector_size);
5163                 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5164                 pe4->ext_pointer = pe4->part_table + 1;
5165                 pe4->changed = 1;
5166                 partitions = 5;
5167         }
5168 }
5169
5170 static void
5171 add_logical(void)
5172 {
5173         if (partitions > 5 || ptes[4].part_table->sys_ind) {
5174                 struct pte *pe = &ptes[partitions];
5175
5176                 pe->sectorbuffer = xzalloc(sector_size);
5177                 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5178                 pe->ext_pointer = pe->part_table + 1;
5179                 pe->offset = 0;
5180                 pe->changed = 1;
5181                 partitions++;
5182         }
5183         add_partition(partitions - 1, LINUX_NATIVE);
5184 }
5185
5186 static void
5187 new_partition(void)
5188 {
5189         int i, free_primary = 0;
5190
5191         if (warn_geometry())
5192                 return;
5193
5194 #ifdef CONFIG_FEATURE_SUN_LABEL
5195         if (label_sun == current_label_type) {
5196                 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5197                 return;
5198         }
5199 #endif
5200 #ifdef CONFIG_FEATURE_SGI_LABEL
5201         if (label_sgi == current_label_type) {
5202                 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5203                 return;
5204         }
5205 #endif
5206 #ifdef CONFIG_FEATURE_AIX_LABEL
5207         if (label_aix == current_label_type) {
5208                 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5209                          "\n\tIf you want to add DOS-type partitions, create"
5210                          "\n\ta new empty DOS partition table first. (Use o.)"
5211                          "\n\tWARNING: "
5212                          "This will destroy the present disk contents.\n"));
5213                 return;
5214         }
5215 #endif
5216
5217         for (i = 0; i < 4; i++)
5218                 free_primary += !ptes[i].part_table->sys_ind;
5219
5220         if (!free_primary && partitions >= MAXIMUM_PARTS) {
5221                 printf(_("The maximum number of partitions has been created\n"));
5222                 return;
5223         }
5224
5225         if (!free_primary) {
5226                 if (extended_offset)
5227                         add_logical();
5228                 else
5229                         printf(_("You must delete some partition and add "
5230                                  "an extended partition first\n"));
5231         } else {
5232                 char c, line[LINE_LENGTH];
5233                 snprintf(line, sizeof(line), "%s\n   %s\n   p   primary "
5234                                                 "partition (1-4)\n",
5235                          "Command action", (extended_offset ?
5236                          "l   logical (5 or over)" : "e   extended"));
5237                 while (1) {
5238                         if ((c = read_char(line)) == 'p' || c == 'P') {
5239                                 i = get_nonexisting_partition(0, 4);
5240                                 if (i >= 0)
5241                                         add_partition(i, LINUX_NATIVE);
5242                                 return;
5243                         }
5244                         else if (c == 'l' && extended_offset) {
5245                                 add_logical();
5246                                 return;
5247                         }
5248                         else if (c == 'e' && !extended_offset) {
5249                                 i = get_nonexisting_partition(0, 4);
5250                                 if (i >= 0)
5251                                         add_partition(i, EXTENDED);
5252                                 return;
5253                         }
5254                         else
5255                                 printf(_("Invalid partition number "
5256                                          "for type `%c'\n"), c);
5257                 }
5258         }
5259 }
5260
5261 static void
5262 write_table(void)
5263 {
5264         int i;
5265
5266         if (label_dos == current_label_type) {
5267                 for (i = 0; i < 3; i++)
5268                         if (ptes[i].changed)
5269                                 ptes[3].changed = 1;
5270                 for (i = 3; i < partitions; i++) {
5271                         struct pte *pe = &ptes[i];
5272
5273                         if (pe->changed) {
5274                                 write_part_table_flag(pe->sectorbuffer);
5275                                 write_sector(pe->offset, pe->sectorbuffer);
5276                         }
5277                 }
5278         }
5279 #ifdef CONFIG_FEATURE_SGI_LABEL
5280         else if (label_sgi == current_label_type) {
5281                 /* no test on change? the printf below might be mistaken */
5282                 sgi_write_table();
5283         }
5284 #endif
5285 #ifdef CONFIG_FEATURE_SUN_LABEL
5286         else if (label_sun == current_label_type) {
5287                 int needw = 0;
5288
5289                 for (i = 0; i < 8; i++)
5290                         if (ptes[i].changed)
5291                                 needw = 1;
5292                 if (needw)
5293                         sun_write_table();
5294         }
5295 #endif
5296
5297         printf(_("The partition table has been altered!\n\n"));
5298         reread_partition_table(1);
5299 }
5300
5301 static void
5302 reread_partition_table(int leave)
5303 {
5304         int error = 0;
5305         int i;
5306
5307         printf(_("Calling ioctl() to re-read partition table.\n"));
5308         sync();
5309         sleep(2);
5310         if ((i = ioctl(fd, BLKRRPART)) != 0) {
5311                 error = errno;
5312         } else {
5313                 /* some kernel versions (1.2.x) seem to have trouble
5314                    rereading the partition table, but if asked to do it
5315                    twice, the second time works. - biro@yggdrasil.com */
5316                 sync();
5317                 sleep(2);
5318                 if ((i = ioctl(fd, BLKRRPART)) != 0)
5319                         error = errno;
5320         }
5321
5322         if (i) {
5323                 printf(_("\nWARNING: Re-reading the partition table "
5324                          "failed with error %d: %s.\n"
5325                          "The kernel still uses the old table.\n"
5326                          "The new table will be used "
5327                          "at the next reboot.\n"),
5328                         error, strerror(error));
5329         }
5330
5331         if (dos_changed)
5332                 printf(
5333                 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5334                 "partitions, please see the fdisk manual page for additional\n"
5335                 "information.\n"));
5336
5337         if (leave) {
5338                 close(fd);
5339
5340                 printf(_("Syncing disks.\n"));
5341                 sync();
5342                 sleep(4);               /* for sync() */
5343                 exit(!!i);
5344         }
5345 }
5346 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
5347
5348 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
5349 #define MAX_PER_LINE    16
5350 static void
5351 print_buffer(char *pbuffer)
5352 {
5353         int i,l;
5354
5355         for (i = 0, l = 0; i < sector_size; i++, l++) {
5356                 if (l == 0)
5357                         printf("0x%03X:", i);
5358                 printf(" %02X", (unsigned char) pbuffer[i]);
5359                 if (l == MAX_PER_LINE - 1) {
5360                         printf("\n");
5361                         l = -1;
5362                 }
5363         }
5364         if (l > 0)
5365                 printf("\n");
5366         printf("\n");
5367 }
5368
5369
5370 static void
5371 print_raw(void)
5372 {
5373         int i;
5374
5375         printf(_("Device: %s\n"), disk_device);
5376 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5377         if (label_sun == current_label_type || label_sgi == current_label_type)
5378                 print_buffer(MBRbuffer);
5379         else
5380 #endif
5381                 for (i = 3; i < partitions; i++)
5382                         print_buffer(ptes[i].sectorbuffer);
5383 }
5384
5385 static void
5386 move_begin(int i)
5387 {
5388         struct pte *pe = &ptes[i];
5389         struct partition *p = pe->part_table;
5390         off_t new, first;
5391
5392         if (warn_geometry())
5393                 return;
5394         if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
5395                 printf(_("Partition %d has no data area\n"), i + 1);
5396                 return;
5397         }
5398         first = get_partition_start(pe);
5399         new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5400                            _("New beginning of data")) - pe->offset;
5401
5402         if (new != get_nr_sects(p)) {
5403                 first = get_nr_sects(p) + get_start_sect(p) - new;
5404                 set_nr_sects(p, first);
5405                 set_start_sect(p, new);
5406                 pe->changed = 1;
5407         }
5408 }
5409
5410 static void
5411 xselect(void)
5412 {
5413         char c;
5414
5415         while (1) {
5416                 putchar('\n');
5417                 c = tolower(read_char(_("Expert command (m for help): ")));
5418                 switch (c) {
5419                 case 'a':
5420 #ifdef CONFIG_FEATURE_SUN_LABEL
5421                         if (label_sun == current_label_type)
5422                                 sun_set_alt_cyl();
5423 #endif
5424                         break;
5425                 case 'b':
5426                         if (label_dos == current_label_type)
5427                                 move_begin(get_partition(0, partitions));
5428                         break;
5429                 case 'c':
5430                         user_cylinders = cylinders =
5431                                 read_int(1, cylinders, 1048576, 0,
5432                                         _("Number of cylinders"));
5433 #ifdef CONFIG_FEATURE_SUN_LABEL
5434                         if (label_sun == current_label_type)
5435                                 sun_set_ncyl(cylinders);
5436 #endif
5437                         if (label_dos == current_label_type)
5438                                 warn_cylinders();
5439                         break;
5440                 case 'd':
5441                         print_raw();
5442                         break;
5443                 case 'e':
5444 #ifdef CONFIG_FEATURE_SGI_LABEL
5445                         if (label_sgi == current_label_type)
5446                                 sgi_set_xcyl();
5447                         else
5448 #endif
5449 #ifdef CONFIG_FEATURE_SUN_LABEL
5450                          if (label_sun == current_label_type)
5451                                 sun_set_xcyl();
5452                          else
5453 #endif
5454                         if (label_dos == current_label_type)
5455                                 x_list_table(1);
5456                         break;
5457                 case 'f':
5458                         if (label_dos == current_label_type)
5459                                 fix_partition_table_order();
5460                         break;
5461                 case 'g':
5462 #ifdef CONFIG_FEATURE_SGI_LABEL
5463                         create_sgilabel();
5464 #endif
5465                         break;
5466                 case 'h':
5467                         user_heads = heads = read_int(1, heads, 256, 0,
5468                                         _("Number of heads"));
5469                         update_units();
5470                         break;
5471                 case 'i':
5472 #ifdef CONFIG_FEATURE_SUN_LABEL
5473                         if (label_sun == current_label_type)
5474                                 sun_set_ilfact();
5475 #endif
5476                         break;
5477                 case 'o':
5478 #ifdef CONFIG_FEATURE_SUN_LABEL
5479                         if (label_sun == current_label_type)
5480                                 sun_set_rspeed();
5481 #endif
5482                         break;
5483                 case 'p':
5484 #ifdef CONFIG_FEATURE_SUN_LABEL
5485                         if (label_sun == current_label_type)
5486                                 list_table(1);
5487                         else
5488 #endif
5489                                 x_list_table(0);
5490                         break;
5491                 case 'q':
5492                         close(fd);
5493                         printf("\n");
5494                         exit(0);
5495                 case 'r':
5496                         return;
5497                 case 's':
5498                         user_sectors = sectors = read_int(1, sectors, 63, 0,
5499                                            _("Number of sectors"));
5500                         if (dos_compatible_flag) {
5501                                 sector_offset = sectors;
5502                                 fprintf(stderr, _("Warning: setting "
5503                                         "sector offset for DOS "
5504                                         "compatiblity\n"));
5505                         }
5506                         update_units();
5507                         break;
5508                 case 'v':
5509                         verify();
5510                         break;
5511                 case 'w':
5512                         write_table();  /* does not return */
5513                         break;
5514                 case 'y':
5515 #ifdef CONFIG_FEATURE_SUN_LABEL
5516                         if (label_sun == current_label_type)
5517                                 sun_set_pcylcount();
5518 #endif
5519                         break;
5520                 default:
5521                         xmenu();
5522                 }
5523         }
5524 }
5525 #endif /* ADVANCED mode */
5526
5527 static int
5528 is_ide_cdrom_or_tape(const char *device)
5529 {
5530         FILE *procf;
5531         char buf[100];
5532         struct stat statbuf;
5533         int is_ide = 0;
5534
5535         /* No device was given explicitly, and we are trying some
5536            likely things.  But opening /dev/hdc may produce errors like
5537            "hdc: tray open or drive not ready"
5538            if it happens to be a CD-ROM drive. It even happens that
5539            the process hangs on the attempt to read a music CD.
5540            So try to be careful. This only works since 2.1.73. */
5541
5542         if (strncmp("/dev/hd", device, 7))
5543                 return 0;
5544
5545         snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5546         procf = fopen(buf, "r");
5547         if (procf != NULL && fgets(buf, sizeof(buf), procf))
5548                 is_ide = (!strncmp(buf, "cdrom", 5) ||
5549                           !strncmp(buf, "tape", 4));
5550         else
5551                 /* Now when this proc file does not exist, skip the
5552                    device when it is read-only. */
5553                 if (stat(device, &statbuf) == 0)
5554                         is_ide = ((statbuf.st_mode & 0222) == 0);
5555
5556         if (procf)
5557                 fclose(procf);
5558         return is_ide;
5559 }
5560
5561
5562 static void
5563 try(const char *device, int user_specified)
5564 {
5565         int gb;
5566
5567         disk_device = device;
5568         if (setjmp(listingbuf))
5569                 return;
5570         if (!user_specified)
5571                 if (is_ide_cdrom_or_tape(device))
5572                         return;
5573         if ((fd = open(disk_device, type_open)) >= 0) {
5574                 gb = get_boot(try_only);
5575                 if (gb > 0) {   /* I/O error */
5576                         close(fd);
5577                 } else if (gb < 0) { /* no DOS signature */
5578                         list_disk_geometry();
5579                         if (label_aix == current_label_type){
5580                                 return;
5581                         }
5582 #ifdef CONFIG_FEATURE_OSF_LABEL
5583                         if (btrydev(device) < 0)
5584 #endif
5585                                 fprintf(stderr,
5586                                         _("Disk %s doesn't contain a valid "
5587                                         "partition table\n"), device);
5588                         close(fd);
5589                 } else {
5590                         close(fd);
5591                         list_table(0);
5592 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5593                         if (label_sun != current_label_type && partitions > 4){
5594                                 delete_partition(ext_index);
5595                         }
5596 #endif
5597                 }
5598         } else {
5599                 /* Ignore other errors, since we try IDE
5600                    and SCSI hard disks which may not be
5601                    installed on the system. */
5602                 if (errno == EACCES) {
5603                         fprintf(stderr, _("Cannot open %s\n"), device);
5604                         return;
5605                 }
5606         }
5607 }
5608
5609 /* for fdisk -l: try all things in /proc/partitions
5610    that look like a partition name (do not end in a digit) */
5611 static void
5612 tryprocpt(void)
5613 {
5614         FILE *procpt;
5615         char line[100], ptname[100], devname[120], *s;
5616         int ma, mi, sz;
5617
5618         procpt = bb_wfopen(PROC_PARTITIONS, "r");
5619
5620         while (fgets(line, sizeof(line), procpt)) {
5621                 if (sscanf(line, " %d %d %d %[^\n ]",
5622                                 &ma, &mi, &sz, ptname) != 4)
5623                         continue;
5624                 for (s = ptname; *s; s++);
5625                 if (isdigit(s[-1]))
5626                         continue;
5627                 sprintf(devname, "/dev/%s", ptname);
5628                 try(devname, 0);
5629         }
5630 #ifdef CONFIG_FEATURE_CLEAN_UP
5631         fclose(procpt);
5632 #endif
5633 }
5634
5635 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5636 static void
5637 unknown_command(int c)
5638 {
5639         printf(_("%c: unknown command\n"), c);
5640 }
5641 #endif
5642
5643 int fdisk_main(int argc, char **argv)
5644 {
5645         int c;
5646 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5647         int optl = 0;
5648 #endif
5649 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5650         int opts = 0;
5651 #endif
5652         /*
5653          * Calls:
5654          *  fdisk -v
5655          *  fdisk -l [-b sectorsize] [-u] device ...
5656          *  fdisk -s [partition] ...
5657          *  fdisk [-b sectorsize] [-u] device
5658          *
5659          * Options -C, -H, -S set the geometry.
5660          *
5661          */
5662         while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5663 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5664                                         "s"
5665 #endif
5666                                         )) != -1) {
5667                 switch (c) {
5668                 case 'b':
5669                         /* Ugly: this sector size is really per device,
5670                            so cannot be combined with multiple disks,
5671                            and te same goes for the C/H/S options.
5672                         */
5673                         sector_size = xatoi_u(optarg);
5674                         if (sector_size != 512 && sector_size != 1024 &&
5675                                 sector_size != 2048)
5676                                 bb_show_usage();
5677                         sector_offset = 2;
5678                         user_set_sector_size = 1;
5679                         break;
5680                 case 'C':
5681                         user_cylinders = xatoi_u(optarg);
5682                         break;
5683                 case 'H':
5684                         user_heads = xatoi_u(optarg);
5685                         if (user_heads <= 0 || user_heads >= 256)
5686                                 user_heads = 0;
5687                         break;
5688                 case 'S':
5689                         user_sectors = xatoi_u(optarg);
5690                         if (user_sectors <= 0 || user_sectors >= 64)
5691                                 user_sectors = 0;
5692                         break;
5693                 case 'l':
5694 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5695                         optl = 1;
5696 #endif
5697                         break;
5698 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5699                 case 's':
5700                         opts = 1;
5701                         break;
5702 #endif
5703                 case 'u':
5704                         display_in_cyl_units = 0;
5705                         break;
5706                 case 'V':
5707                 case 'v':
5708                         printf("fdisk v" UTIL_LINUX_VERSION "\n");
5709                         return 0;
5710                 default:
5711                         bb_show_usage();
5712                 }
5713         }
5714
5715         if (user_set_sector_size && argc-optind != 1)
5716                 printf(_("Warning: the -b (set sector size) option should"
5717                          " be used with one specified device\n"));
5718
5719 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5720         if (optl) {
5721                 nowarn = 1;
5722 #endif
5723                 type_open = O_RDONLY;
5724                 if (argc > optind) {
5725                         int k;
5726 #if __GNUC__
5727                         /* avoid gcc warning:
5728                            variable `k' might be clobbered by `longjmp' */
5729                         (void)&k;
5730 #endif
5731                         listing = 1;
5732                         for (k = optind; k < argc; k++)
5733                                 try(argv[k], 1);
5734                 } else {
5735                         /* we no longer have default device names */
5736                         /* but, we can use /proc/partitions instead */
5737                         tryprocpt();
5738                 }
5739                 return 0;
5740 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5741         }
5742 #endif
5743
5744 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5745         if (opts) {
5746                 long size;
5747                 int j;
5748
5749                 nowarn = 1;
5750                 type_open = O_RDONLY;
5751
5752                 opts = argc - optind;
5753                 if (opts <= 0)
5754                         bb_show_usage();
5755
5756                 for (j = optind; j < argc; j++) {
5757                         disk_device = argv[j];
5758                         if ((fd = open(disk_device, type_open)) < 0)
5759                                 fdisk_fatal(unable_to_open);
5760                         if (ioctl(fd, BLKGETSIZE, &size))
5761                                 fdisk_fatal(ioctl_error);
5762                         close(fd);
5763                         if (opts == 1)
5764                                 printf("%ld\n", size/2);
5765                         else
5766                                 printf("%s: %ld\n", argv[j], size/2);
5767                 }
5768                 return 0;
5769         }
5770 #endif
5771
5772 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5773         if (argc-optind == 1)
5774                 disk_device = argv[optind];
5775         else
5776                 bb_show_usage();
5777
5778         get_boot(fdisk);
5779
5780 #ifdef CONFIG_FEATURE_OSF_LABEL
5781         if (label_osf == current_label_type) {
5782                 /* OSF label, and no DOS label */
5783                 printf(_("Detected an OSF/1 disklabel on %s, entering "
5784                          "disklabel mode.\n"),
5785                            disk_device);
5786                 bselect();
5787                 /*Why do we do this?  It seems to be counter-intuitive*/
5788                 current_label_type = label_dos;
5789                 /* If we return we may want to make an empty DOS label? */
5790         }
5791 #endif
5792
5793         while (1) {
5794                 putchar('\n');
5795                 c = tolower(read_char(_("Command (m for help): ")));
5796                 switch (c) {
5797                 case 'a':
5798                         if (label_dos == current_label_type)
5799                                 toggle_active(get_partition(1, partitions));
5800 #ifdef CONFIG_FEATURE_SUN_LABEL
5801                         else if (label_sun == current_label_type)
5802                                 toggle_sunflags(get_partition(1, partitions),
5803                                                 0x01);
5804 #endif
5805 #ifdef CONFIG_FEATURE_SGI_LABEL
5806                         else if (label_sgi == current_label_type)
5807                                 sgi_set_bootpartition(
5808                                         get_partition(1, partitions));
5809 #endif
5810                         else
5811                                 unknown_command(c);
5812                         break;
5813                 case 'b':
5814 #ifdef CONFIG_FEATURE_SGI_LABEL
5815                         if (label_sgi == current_label_type) {
5816                                 printf(_("\nThe current boot file is: %s\n"),
5817                                         sgi_get_bootfile());
5818                                 if (read_chars(_("Please enter the name of the "
5819                                                    "new boot file: ")) == '\n')
5820                                         printf(_("Boot file unchanged\n"));
5821                                 else
5822                                         sgi_set_bootfile(line_ptr);
5823                         } else
5824 #endif
5825 #ifdef CONFIG_FEATURE_OSF_LABEL
5826                                 bselect();
5827 #endif
5828                         break;
5829                 case 'c':
5830                         if (label_dos == current_label_type)
5831                                 toggle_dos_compatibility_flag();
5832 #ifdef CONFIG_FEATURE_SUN_LABEL
5833                         else if (label_sun == current_label_type)
5834                                 toggle_sunflags(get_partition(1, partitions),
5835                                                 0x10);
5836 #endif
5837 #ifdef CONFIG_FEATURE_SGI_LABEL
5838                         else if (label_sgi == current_label_type)
5839                                 sgi_set_swappartition(
5840                                                 get_partition(1, partitions));
5841 #endif
5842                         else
5843                                 unknown_command(c);
5844                         break;
5845                 case 'd':
5846                         {
5847                                 int j;
5848 #ifdef CONFIG_FEATURE_SGI_LABEL
5849                         /* If sgi_label then don't use get_existing_partition,
5850                            let the user select a partition, since
5851                            get_existing_partition() only works for Linux-like
5852                            partition tables */
5853                                 if (label_sgi != current_label_type) {
5854                                         j = get_existing_partition(1, partitions);
5855                                 } else {
5856                                         j = get_partition(1, partitions);
5857                                 }
5858 #else
5859                                 j = get_existing_partition(1, partitions);
5860 #endif
5861                                 if (j >= 0)
5862                                         delete_partition(j);
5863                         }
5864                         break;
5865                 case 'i':
5866 #ifdef CONFIG_FEATURE_SGI_LABEL
5867                         if (label_sgi == current_label_type)
5868                                 create_sgiinfo();
5869                         else
5870 #endif
5871                                 unknown_command(c);
5872                 case 'l':
5873                         list_types(get_sys_types());
5874                         break;
5875                 case 'm':
5876                         menu();
5877                         break;
5878                 case 'n':
5879                         new_partition();
5880                         break;
5881                 case 'o':
5882                         create_doslabel();
5883                         break;
5884                 case 'p':
5885                         list_table(0);
5886                         break;
5887                 case 'q':
5888                         close(fd);
5889                         printf("\n");
5890                         return 0;
5891                 case 's':
5892 #ifdef CONFIG_FEATURE_SUN_LABEL
5893                         create_sunlabel();
5894 #endif
5895                         break;
5896                 case 't':
5897                         change_sysid();
5898                         break;
5899                 case 'u':
5900                         change_units();
5901                         break;
5902                 case 'v':
5903                         verify();
5904                         break;
5905                 case 'w':
5906                         write_table();          /* does not return */
5907                         break;
5908 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
5909                 case 'x':
5910 #ifdef CONFIG_FEATURE_SGI_LABEL
5911                         if (label_sgi == current_label_type) {
5912                                 fprintf(stderr,
5913                                         _("\n\tSorry, no experts menu for SGI "
5914                                         "partition tables available.\n\n"));
5915                         } else
5916 #endif
5917
5918                                 xselect();
5919                         break;
5920 #endif
5921                 default:
5922                         unknown_command(c);
5923                         menu();
5924                 }
5925         }
5926         return 0;
5927 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
5928 }