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