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