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