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