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