source: trunk/mindi-busybox/util-linux/fdisk.c @ 956

Last change on this file since 956 was 821, checked in by bruno, 13 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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