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