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