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