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