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