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