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