fix from Kolbjørn Barmen for building for m68k targets
[platform/upstream/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 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
1447         d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
1448 #endif
1449
1450 #if !defined (__alpha__)
1451         d->d_flags = BSD_D_DOSPART;
1452 #else
1453         d->d_flags = 0;
1454 #endif
1455         d->d_secsize = SECTOR_SIZE;           /* bytes/sector  */
1456         d->d_nsectors = sectors;            /* sectors/track */
1457         d->d_ntracks = heads;               /* tracks/cylinder (heads) */
1458         d->d_ncylinders = cylinders;
1459         d->d_secpercyl  = sectors * heads;/* sectors/cylinder */
1460         if (d->d_secpercyl == 0)
1461                 d->d_secpercyl = 1;           /* avoid segfaults */
1462         d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
1463
1464         d->d_rpm = 3600;
1465         d->d_interleave = 1;
1466         d->d_trackskew = 0;
1467         d->d_cylskew = 0;
1468         d->d_headswitch = 0;
1469         d->d_trkseek = 0;
1470
1471         d->d_magic2 = BSD_DISKMAGIC;
1472         d->d_bbsize = BSD_BBSIZE;
1473         d->d_sbsize = BSD_SBSIZE;
1474
1475 #if !defined (__alpha__)
1476         d->d_npartitions = 4;
1477         pp = &d->d_partitions[2];             /* Partition C should be
1478                                                    the NetBSD partition */
1479         pp->p_offset = get_start_sect(p);
1480         pp->p_size   = get_nr_sects(p);
1481         pp->p_fstype = BSD_FS_UNUSED;
1482         pp = &d->d_partitions[3];             /* Partition D should be
1483                                                    the whole disk */
1484         pp->p_offset = 0;
1485         pp->p_size   = d->d_secperunit;
1486         pp->p_fstype = BSD_FS_UNUSED;
1487 #elif defined (__alpha__)
1488         d->d_npartitions = 3;
1489         pp = &d->d_partitions[2];             /* Partition C should be
1490                                                    the whole disk */
1491         pp->p_offset = 0;
1492         pp->p_size   = d->d_secperunit;
1493         pp->p_fstype = BSD_FS_UNUSED;
1494 #endif
1495
1496         return 1;
1497 }
1498
1499 /*
1500  * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1501  * If it has the right magic, return 1.
1502  */
1503 static int
1504 xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1505 {
1506         int t, sector;
1507
1508         /* p is used only to get the starting sector */
1509 #if !defined (__alpha__)
1510         sector = (p ? get_start_sect(p) : 0);
1511 #elif defined (__alpha__)
1512         sector = 0;
1513 #endif
1514
1515         if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1516                 fdisk_fatal(unable_to_seek);
1517         if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1518                 fdisk_fatal(unable_to_read);
1519
1520         memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1521                    sizeof(struct xbsd_disklabel));
1522
1523         if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
1524                 return 0;
1525
1526         for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1527                 d->d_partitions[t].p_size   = 0;
1528                 d->d_partitions[t].p_offset = 0;
1529                 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
1530         }
1531
1532         if (d->d_npartitions > BSD_MAXPARTITIONS)
1533                 fprintf(stderr, _("Warning: too many partitions "
1534                                 "(%d, maximum is %d).\n"),
1535                         d->d_npartitions, BSD_MAXPARTITIONS);
1536         return 1;
1537 }
1538
1539 static int
1540 xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1541 {
1542         unsigned int sector;
1543
1544 #if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1545         sector = get_start_sect(p) + BSD_LABELSECTOR;
1546 #else
1547         sector = BSD_LABELSECTOR;
1548 #endif
1549
1550         d->d_checksum = 0;
1551         d->d_checksum = xbsd_dkcksum (d);
1552
1553         /* This is necessary if we want to write the bootstrap later,
1554            otherwise we'd write the old disklabel with the bootstrap.
1555         */
1556         memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1557                 d, sizeof(struct xbsd_disklabel));
1558
1559 #if defined (__alpha__) && BSD_LABELSECTOR == 0
1560         alpha_bootblock_checksum (disklabelbuffer);
1561         if (lseek(fd, 0, SEEK_SET) == -1)
1562                 fdisk_fatal(unable_to_seek);
1563         if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1564                 fdisk_fatal(unable_to_write);
1565 #else
1566         if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1567                 fdisk_fatal(unable_to_seek);
1568         if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1569                 fdisk_fatal(unable_to_write);
1570 #endif
1571         sync_disks();
1572         return 1;
1573 }
1574
1575
1576 #if !defined (__alpha__)
1577 static int
1578 xbsd_translate_fstype(int linux_type)
1579 {
1580         switch (linux_type) {
1581         case 0x01: /* DOS 12-bit FAT   */
1582         case 0x04: /* DOS 16-bit <32M  */
1583         case 0x06: /* DOS 16-bit >=32M */
1584         case 0xe1: /* DOS access       */
1585         case 0xe3: /* DOS R/O          */
1586         case 0xf2: /* DOS secondary    */
1587                 return BSD_FS_MSDOS;
1588         case 0x07: /* OS/2 HPFS        */
1589                 return BSD_FS_HPFS;
1590         default:
1591                 return BSD_FS_OTHER;
1592         }
1593 }
1594
1595 static void
1596 xbsd_link_part(void)
1597 {
1598         int k, i;
1599         struct partition *p;
1600
1601         k = get_partition(1, partitions);
1602
1603         if (!xbsd_check_new_partition(&i))
1604                 return;
1605
1606         p = get_part_table(k);
1607
1608         xbsd_dlabel.d_partitions[i].p_size   = get_nr_sects(p);
1609         xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1610         xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1611 }
1612 #endif
1613
1614 #if defined (__alpha__)
1615
1616 #if !defined(__GLIBC__)
1617 typedef unsigned long long uint64_t;
1618 #endif
1619
1620 static void
1621 alpha_bootblock_checksum(char *boot)
1622 {
1623         uint64_t *dp, sum;
1624         int i;
1625
1626         dp = (uint64_t *)boot;
1627         sum = 0;
1628         for (i = 0; i < 63; i++)
1629                 sum += dp[i];
1630         dp[63] = sum;
1631 }
1632 #endif /* __alpha__ */
1633
1634 #endif /* OSF_LABEL */
1635
1636 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1637 static inline unsigned short
1638 __swap16(unsigned short x)
1639 {
1640         return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
1641 }
1642
1643 static inline uint32_t
1644 __swap32(uint32_t x)
1645 {
1646         return (((x & 0xFF) << 24) |
1647                 ((x & 0xFF00) << 8) |
1648                 ((x & 0xFF0000) >> 8) |
1649                 ((x & 0xFF000000) >> 24));
1650 }
1651 #endif
1652
1653 #ifdef CONFIG_FEATURE_SGI_LABEL
1654 /*
1655  *
1656  * fdisksgilabel.c
1657  *
1658  * Copyright (C) Andreas Neuper, Sep 1998.
1659  *      This file may be modified and redistributed under
1660  *      the terms of the GNU Public License.
1661  *
1662  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1663  *      Internationalization
1664  */
1665
1666
1667 static int sgi_other_endian;
1668 static int debug;
1669 static short sgi_volumes = 1;
1670
1671 /*
1672  * only dealing with free blocks here
1673  */
1674
1675 typedef struct {
1676         unsigned int first;
1677         unsigned int last;
1678 } freeblocks;
1679 static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1680
1681 static void
1682 setfreelist(int i, unsigned int f, unsigned int l)
1683 {
1684         freelist[i].first = f;
1685         freelist[i].last = l;
1686 }
1687
1688 static void
1689 add2freelist(unsigned int f, unsigned int l)
1690 {
1691         int i;
1692         for (i = 0; i < 17 ; i++)
1693                 if (freelist[i].last == 0)
1694                         break;
1695         setfreelist(i, f, l);
1696 }
1697
1698 static void
1699 clearfreelist(void)
1700 {
1701         int i;
1702
1703         for (i = 0; i < 17 ; i++)
1704                 setfreelist(i, 0, 0);
1705 }
1706
1707 static unsigned int
1708 isinfreelist(unsigned int b)
1709 {
1710         int i;
1711
1712         for (i = 0; i < 17 ; i++)
1713                 if (freelist[i].first <= b && freelist[i].last >= b)
1714                         return freelist[i].last;
1715         return 0;
1716 }
1717         /* return last vacant block of this stride (never 0). */
1718         /* the '>=' is not quite correct, but simplifies the code */
1719 /*
1720  * end of free blocks section
1721  */
1722
1723 static const struct systypes sgi_sys_types[] = {
1724 /* SGI_VOLHDR   */      { "\x00" "SGI volhdr"   },
1725 /* 0x01         */      { "\x01" "SGI trkrepl"  },
1726 /* 0x02         */      { "\x02" "SGI secrepl"  },
1727 /* SGI_SWAP     */      { "\x03" "SGI raw"      },
1728 /* 0x04         */      { "\x04" "SGI bsd"      },
1729 /* 0x05         */      { "\x05" "SGI sysv"     },
1730 /* ENTIRE_DISK  */      { "\x06" "SGI volume"   },
1731 /* SGI_EFS      */      { "\x07" "SGI efs"      },
1732 /* 0x08         */      { "\x08" "SGI lvol"     },
1733 /* 0x09         */      { "\x09" "SGI rlvol"    },
1734 /* SGI_XFS      */      { "\x0a" "SGI xfs"      },
1735 /* SGI_XFSLOG   */      { "\x0b" "SGI xfslog"   },
1736 /* SGI_XLV      */      { "\x0c" "SGI xlv"      },
1737 /* SGI_XVM      */      { "\x0d" "SGI xvm"      },
1738 /* LINUX_SWAP   */      { "\x82" "Linux swap"   },
1739 /* LINUX_NATIVE */      { "\x83" "Linux native" },
1740 /* LINUX_LVM    */      { "\x8d" "Linux LVM"    },
1741 /* LINUX_RAID   */      { "\xfd" "Linux RAID"   },
1742                         { NULL             }
1743 };
1744
1745
1746 static int
1747 sgi_get_nsect(void)
1748 {
1749         return SGI_SSWAP16(sgilabel->devparam.nsect);
1750 }
1751
1752 static int
1753 sgi_get_ntrks(void)
1754 {
1755         return SGI_SSWAP16(sgilabel->devparam.ntrks);
1756 }
1757
1758 static unsigned int
1759 two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1760 {
1761         int i = 0;
1762         unsigned int sum = 0;
1763
1764         size /= sizeof(unsigned int);
1765         for (i = 0; i < size; i++)
1766                 sum -= SGI_SSWAP32(base[i]);
1767         return sum;
1768 }
1769
1770 static int
1771 check_sgi_label(void)
1772 {
1773         if (sizeof(sgilabel) > 512) {
1774                 fprintf(stderr,
1775                         _("According to MIPS Computer Systems, Inc the "
1776                         "Label must not contain more than 512 bytes\n"));
1777                 exit(1);
1778         }
1779
1780         if (sgilabel->magic != SGI_LABEL_MAGIC
1781          && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1782                 current_label_type = label_dos;
1783                 return 0;
1784         }
1785
1786         sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1787         /*
1788          * test for correct checksum
1789          */
1790         if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1791                                 sizeof(*sgilabel))) {
1792                 fprintf(stderr,
1793                         _("Detected sgi disklabel with wrong checksum.\n"));
1794         }
1795         update_units();
1796         current_label_type = label_sgi;
1797         partitions = 16;
1798         sgi_volumes = 15;
1799         return 1;
1800 }
1801
1802 static unsigned int
1803 sgi_get_start_sector(int i)
1804 {
1805         return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1806 }
1807
1808 static unsigned int
1809 sgi_get_num_sectors(int i)
1810 {
1811         return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1812 }
1813
1814 static int
1815 sgi_get_sysid(int i)
1816 {
1817         return SGI_SSWAP32(sgilabel->partitions[i].id);
1818 }
1819
1820 static int
1821 sgi_get_bootpartition(void)
1822 {
1823         return SGI_SSWAP16(sgilabel->boot_part);
1824 }
1825
1826 static int
1827 sgi_get_swappartition(void)
1828 {
1829         return SGI_SSWAP16(sgilabel->swap_part);
1830 }
1831
1832 static void
1833 sgi_list_table(int xtra)
1834 {
1835         int i, w, wd;
1836         int kpi = 0;                /* kernel partition ID */
1837
1838         if(xtra) {
1839                 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1840                         "%d cylinders, %d physical cylinders\n"
1841                         "%d extra sects/cyl, interleave %d:1\n"
1842                         "%s\n"
1843                         "Units = %s of %d * 512 bytes\n\n"),
1844                         disk_device, heads, sectors, cylinders,
1845                         SGI_SSWAP16(sgiparam.pcylcount),
1846                         SGI_SSWAP16(sgiparam.sparecyl),
1847                         SGI_SSWAP16(sgiparam.ilfact),
1848                         (char *)sgilabel,
1849                         str_units(PLURAL), units_per_sector);
1850         } else {
1851                 printf( _("\nDisk %s (SGI disk label): "
1852                         "%d heads, %d sectors, %d cylinders\n"
1853                         "Units = %s of %d * 512 bytes\n\n"),
1854                         disk_device, heads, sectors, cylinders,
1855                         str_units(PLURAL), units_per_sector );
1856         }
1857
1858         w = strlen(disk_device);
1859         wd = strlen(_("Device"));
1860         if (w < wd)
1861         w = wd;
1862
1863         printf(_("----- partitions -----\n"
1864                 "Pt# %*s  Info     Start       End   Sectors  Id  System\n"),
1865                 w + 2, _("Device"));
1866         for (i = 0 ; i < partitions; i++) {
1867                 if( sgi_get_num_sectors(i) || debug ) {
1868                         uint32_t start = sgi_get_start_sector(i);
1869                         uint32_t len = sgi_get_num_sectors(i);
1870                         kpi++;              /* only count nonempty partitions */
1871                         printf(
1872                         "%2d: %s %4s %9ld %9ld %9ld  %2x  %s\n",
1873 /* fdisk part number */ i+1,
1874 /* device */            partname(disk_device, kpi, w+3),
1875 /* flags */             (sgi_get_swappartition() == i) ? "swap" :
1876 /* flags */             (sgi_get_bootpartition() == i) ? "boot" : "    ",
1877 /* start */             (long) scround(start),
1878 /* end */               (long) scround(start+len)-1,
1879 /* no odd flag on end */(long) len,
1880 /* type id */           sgi_get_sysid(i),
1881 /* type name */         partition_type(sgi_get_sysid(i)));
1882                 }
1883         }
1884         printf(_("----- Bootinfo -----\nBootfile: %s\n"
1885                 "----- Directory Entries -----\n"),
1886                 sgilabel->boot_file);
1887         for (i = 0 ; i < sgi_volumes; i++) {
1888                 if (sgilabel->directory[i].vol_file_size) {
1889                         uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1890                         uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1891                         unsigned char *name = sgilabel->directory[i].vol_file_name;
1892
1893                         printf(_("%2d: %-10s sector%5u size%8u\n"),
1894                                 i, (char*)name, (unsigned int) start, (unsigned int) len);
1895                 }
1896         }
1897 }
1898
1899 static void
1900 sgi_set_bootpartition(int i)
1901 {
1902         sgilabel->boot_part = SGI_SSWAP16(((short)i));
1903 }
1904
1905 static unsigned int
1906 sgi_get_lastblock(void)
1907 {
1908         return heads * sectors * cylinders;
1909 }
1910
1911 static void
1912 sgi_set_swappartition(int i)
1913 {
1914         sgilabel->swap_part = SGI_SSWAP16(((short)i));
1915 }
1916
1917 static int
1918 sgi_check_bootfile(const char* aFile)
1919 {
1920         if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1921                 printf(_("\nInvalid Bootfile!\n"
1922                         "\tThe bootfile must be an absolute non-zero pathname,\n"
1923                         "\te.g. \"/unix\" or \"/unix.save\".\n"));
1924                 return 0;
1925         } else {
1926                 if (strlen(aFile) > 16) {
1927                         printf(_("\n\tName of Bootfile too long:  "
1928                                 "16 bytes maximum.\n"));
1929                         return 0;
1930                 } else {
1931                         if (aFile[0] != '/') {
1932                                 printf(_("\n\tBootfile must have a "
1933                                         "fully qualified pathname.\n"));
1934                                 return 0;
1935                         }
1936                 }
1937         }
1938         if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
1939                 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1940                          "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
1941                 /* filename is correct and did change */
1942                 return 1;
1943         }
1944         return 0;   /* filename did not change */
1945 }
1946
1947 static const char *
1948 sgi_get_bootfile(void)
1949 {
1950         return (char*)sgilabel->boot_file;
1951 }
1952
1953 static void
1954 sgi_set_bootfile(const char* aFile)
1955 {
1956         int i = 0;
1957
1958         if (sgi_check_bootfile(aFile)) {
1959                 while (i < 16) {
1960                         if ((aFile[i] != '\n')  /* in principle caught again by next line */
1961                          && (strlen(aFile) > i))
1962                                 sgilabel->boot_file[i] = aFile[i];
1963                         else
1964                                 sgilabel->boot_file[i] = 0;
1965                         i++;
1966                 }
1967                 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
1968         }
1969 }
1970
1971 static void
1972 create_sgiinfo(void)
1973 {
1974         /* I keep SGI's habit to write the sgilabel to the second block */
1975         sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1976         sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1977         strcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel");
1978 }
1979
1980 static sgiinfo *fill_sgiinfo(void);
1981
1982 static void
1983 sgi_write_table(void)
1984 {
1985         sgilabel->csum = 0;
1986         sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1987                         (unsigned int*)sgilabel, sizeof(*sgilabel)));
1988         assert(two_s_complement_32bit_sum(
1989                 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
1990
1991         if (lseek(fd, 0, SEEK_SET) < 0)
1992                 fdisk_fatal(unable_to_seek);
1993         if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1994                 fdisk_fatal(unable_to_write);
1995         if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
1996                 /*
1997                  * keep this habit of first writing the "sgilabel".
1998                  * I never tested whether it works without (AN 981002).
1999                  */
2000                 sgiinfo *info = fill_sgiinfo();
2001                 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2002                 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2003                         fdisk_fatal(unable_to_seek);
2004                 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2005                         fdisk_fatal(unable_to_write);
2006                 free(info);
2007         }
2008 }
2009
2010 static int
2011 compare_start(int *x, int *y)
2012 {
2013         /*
2014          * sort according to start sectors
2015          * and prefers largest partition:
2016          * entry zero is entire disk entry
2017          */
2018         unsigned int i = *x;
2019         unsigned int j = *y;
2020         unsigned int a = sgi_get_start_sector(i);
2021         unsigned int b = sgi_get_start_sector(j);
2022         unsigned int c = sgi_get_num_sectors(i);
2023         unsigned int d = sgi_get_num_sectors(j);
2024
2025         if (a == b)
2026                 return (d > c) ? 1 : (d == c) ? 0 : -1;
2027         return (a > b) ? 1 : -1;
2028 }
2029
2030
2031 static int
2032 verify_sgi(int verbose)
2033 {
2034         int Index[16];      /* list of valid partitions */
2035         int sortcount = 0;  /* number of used partitions, i.e. non-zero lengths */
2036         int entire = 0, i = 0;
2037         unsigned int start = 0;
2038         long long gap = 0;      /* count unused blocks */
2039         unsigned int lastblock = sgi_get_lastblock();
2040
2041         clearfreelist();
2042         for (i = 0; i < 16; i++) {
2043                 if (sgi_get_num_sectors(i) != 0) {
2044                         Index[sortcount++] = i;
2045                         if (sgi_get_sysid(i) == ENTIRE_DISK) {
2046                                 if (entire++ == 1) {
2047                                         if (verbose)
2048                                                 printf(_("More than one entire disk entry present.\n"));
2049                                 }
2050                         }
2051                 }
2052         }
2053         if (sortcount == 0) {
2054                 if (verbose)
2055                         printf(_("No partitions defined\n"));
2056                 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2057         }
2058         qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2059         if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2060                 if ((Index[0] != 10) && verbose)
2061                         printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2062                 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2063                         printf(_("The entire disk partition should start "
2064                                 "at block 0,\n"
2065                                 "not at diskblock %d.\n"),
2066                 sgi_get_start_sector(Index[0]));
2067                 if (debug)      /* I do not understand how some disks fulfil it */
2068                         if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2069                                 printf(_("The entire disk partition is only %d diskblock large,\n"
2070                                         "but the disk is %d diskblocks long.\n"),
2071                 sgi_get_num_sectors(Index[0]), lastblock);
2072                 lastblock = sgi_get_num_sectors(Index[0]);
2073         } else {
2074                 if (verbose)
2075                         printf(_("One Partition (#11) should cover the entire disk.\n"));
2076                 if (debug > 2)
2077                         printf("sysid=%d\tpartition=%d\n",
2078                                 sgi_get_sysid(Index[0]), Index[0]+1);
2079         }
2080         for (i = 1, start = 0; i < sortcount; i++) {
2081                 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2082
2083                 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2084                         if (debug)      /* I do not understand how some disks fulfil it */
2085                                 if (verbose)
2086                                         printf(_("Partition %d does not start on cylinder boundary.\n"),
2087                                                 Index[i]+1);
2088                 }
2089                 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2090                         if (debug)      /* I do not understand how some disks fulfil it */
2091                                 if (verbose)
2092                                         printf(_("Partition %d does not end on cylinder boundary.\n"),
2093                                                 Index[i]+1);
2094                 }
2095                 /* We cannot handle several "entire disk" entries. */
2096                 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2097                 if (start > sgi_get_start_sector(Index[i])) {
2098                         if (verbose)
2099                                 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2100                                         Index[i-1]+1, Index[i]+1,
2101                                         start - sgi_get_start_sector(Index[i]));
2102                         if (gap >  0) gap = -gap;
2103                         if (gap == 0) gap = -1;
2104                 }
2105                 if (start < sgi_get_start_sector(Index[i])) {
2106                         if (verbose)
2107                                 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2108                                         sgi_get_start_sector(Index[i]) - start,
2109                                         start, sgi_get_start_sector(Index[i])-1);
2110                         gap += sgi_get_start_sector(Index[i]) - start;
2111                         add2freelist(start, sgi_get_start_sector(Index[i]));
2112                 }
2113                 start = sgi_get_start_sector(Index[i])
2114                            + sgi_get_num_sectors(Index[i]);
2115                 if (debug > 1) {
2116                         if (verbose)
2117                                 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2118                                         sgi_get_start_sector(Index[i]),
2119                                         sgi_get_num_sectors(Index[i]),
2120                                         sgi_get_sysid(Index[i]));
2121                 }
2122         }
2123         if (start < lastblock) {
2124                 if (verbose)
2125                         printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2126                                 lastblock - start, start, lastblock-1);
2127                 gap += lastblock - start;
2128                 add2freelist(start, lastblock);
2129         }
2130         /*
2131          * Done with arithmetics
2132          * Go for details now
2133          */
2134         if (verbose) {
2135                 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2136                         printf(_("\nThe boot partition does not exist.\n"));
2137                 }
2138                 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2139                         printf(_("\nThe swap partition does not exist.\n"));
2140                 } else {
2141                         if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2142                          && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2143                                 printf(_("\nThe swap partition has no swap type.\n"));
2144                 }
2145                 if (sgi_check_bootfile("/unix"))
2146                         printf(_("\tYou have chosen an unusual boot file name.\n"));
2147         }
2148         return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
2149 }
2150
2151 static int
2152 sgi_gaps(void)
2153 {
2154         /*
2155          * returned value is:
2156          *  = 0 : disk is properly filled to the rim
2157          *  < 0 : there is an overlap
2158          *  > 0 : there is still some vacant space
2159          */
2160         return verify_sgi(0);
2161 }
2162
2163 static void
2164 sgi_change_sysid(int i, int sys)
2165 {
2166         if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2167                 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2168                 return;
2169         }
2170         if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2171          && (sgi_get_start_sector(i) < 1) ) {
2172                 read_chars(
2173                         _("It is highly recommended that the partition at offset 0\n"
2174                         "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2175                         "retrieve from its directory standalone tools like sash and fx.\n"
2176                         "Only the \"SGI volume\" entire disk section may violate this.\n"
2177                         "Type YES if you are sure about tagging this partition differently.\n"));
2178                 if (strcmp(line_ptr, _("YES\n")))
2179                         return;
2180         }
2181         sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2182 }
2183
2184 /* returns partition index of first entry marked as entire disk */
2185 static int
2186 sgi_entire(void)
2187 {
2188         int i;
2189
2190         for (i = 0; i < 16; i++)
2191                 if (sgi_get_sysid(i) == SGI_VOLUME)
2192                         return i;
2193         return -1;
2194 }
2195
2196 static void
2197 sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2198 {
2199         sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2200         sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2201         sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2202         set_changed(i);
2203         if (sgi_gaps() < 0)     /* rebuild freelist */
2204                 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2205 }
2206
2207 static void
2208 sgi_set_entire(void)
2209 {
2210         int n;
2211
2212         for (n = 10; n < partitions; n++) {
2213                 if(!sgi_get_num_sectors(n) ) {
2214                         sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2215                         break;
2216                 }
2217         }
2218 }
2219
2220 static void
2221 sgi_set_volhdr(void)
2222 {
2223         int n;
2224
2225         for (n = 8; n < partitions; n++) {
2226         if (!sgi_get_num_sectors(n)) {
2227                 /*
2228                  * 5 cylinders is an arbitrary value I like
2229                  * IRIX 5.3 stored files in the volume header
2230                  * (like sash, symmon, fx, ide) with ca. 3200
2231                  * sectors.
2232                  */
2233                 if (heads * sectors * 5 < sgi_get_lastblock())
2234                         sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2235                         break;
2236                 }
2237         }
2238 }
2239
2240 static void
2241 sgi_delete_partition(int i)
2242 {
2243         sgi_set_partition(i, 0, 0, 0);
2244 }
2245
2246 static void
2247 sgi_add_partition(int n, int sys)
2248 {
2249         char mesg[256];
2250         unsigned int first = 0, last = 0;
2251
2252         if (n == 10) {
2253                 sys = SGI_VOLUME;
2254         } else if (n == 8) {
2255                 sys = 0;
2256         }
2257         if(sgi_get_num_sectors(n)) {
2258                 printf(_("Partition %d is already defined.  Delete "
2259                         "it before re-adding it.\n"), n + 1);
2260                 return;
2261         }
2262         if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2263                 printf(_("Attempting to generate entire disk entry automatically.\n"));
2264                 sgi_set_entire();
2265                 sgi_set_volhdr();
2266         }
2267         if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2268                 printf(_("The entire disk is already covered with partitions.\n"));
2269                 return;
2270         }
2271         if (sgi_gaps() < 0) {
2272                 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2273                 return;
2274         }
2275         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2276         while (1) {
2277                 if(sys == SGI_VOLUME) {
2278                         last = sgi_get_lastblock();
2279                         first = read_int(0, 0, last-1, 0, mesg);
2280                         if (first != 0) {
2281                                 printf(_("It is highly recommended that eleventh partition\n"
2282                                                 "covers the entire disk and is of type `SGI volume'\n"));
2283                         }
2284                 } else {
2285                         first = freelist[0].first;
2286                         last  = freelist[0].last;
2287                         first = read_int(scround(first), scround(first), scround(last)-1,
2288                                 0, mesg);
2289                 }
2290                 if (display_in_cyl_units)
2291                         first *= units_per_sector;
2292                 else
2293                         first = first; /* align to cylinder if you know how ... */
2294                 if(!last )
2295                         last = isinfreelist(first);
2296                 if(last == 0) {
2297                         printf(_("You will get a partition overlap on the disk. "
2298                                 "Fix it first!\n"));
2299                 } else
2300                         break;
2301         }
2302         snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2303         last = read_int(scround(first), scround(last)-1, scround(last)-1,
2304                         scround(first), mesg)+1;
2305         if (display_in_cyl_units)
2306                 last *= units_per_sector;
2307         else
2308                 last = last; /* align to cylinder if You know how ... */
2309         if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2310                 printf(_("It is highly recommended that eleventh partition\n"
2311                         "covers the entire disk and is of type `SGI volume'\n"));
2312         sgi_set_partition(n, first, last-first, sys);
2313 }
2314
2315 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
2316 static void
2317 create_sgilabel(void)
2318 {
2319         struct hd_geometry geometry;
2320         struct {
2321                 unsigned int start;
2322                 unsigned int nsect;
2323                 int sysid;
2324         } old[4];
2325         int i = 0;
2326         long longsectors;               /* the number of sectors on the device */
2327         int res;                        /* the result from the ioctl */
2328         int sec_fac;                    /* the sector factor */
2329
2330         sec_fac = sector_size / 512;    /* determine the sector factor */
2331
2332         fprintf( stderr,
2333                 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2334                 "until you decide to write them. After that, of course, the previous\n"
2335                 "content will be unrecoverably lost.\n\n"));
2336
2337         sgi_other_endian = (BB_LITTLE_ENDIAN);
2338         res = ioctl(fd, BLKGETSIZE, &longsectors);
2339         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2340                 heads = geometry.heads;
2341                 sectors = geometry.sectors;
2342                 if (res == 0) {
2343                         /* the get device size ioctl was successful */
2344                         cylinders = longsectors / (heads * sectors);
2345                         cylinders /= sec_fac;
2346                 } else {
2347                         /* otherwise print error and use truncated version */
2348                         cylinders = geometry.cylinders;
2349                         fprintf(stderr,
2350                                 _("Warning:  BLKGETSIZE ioctl failed on %s.  "
2351                                 "Using geometry cylinder value of %d.\n"
2352                                 "This value may be truncated for devices"
2353                                 " > 33.8 GB.\n"), disk_device, cylinders);
2354                 }
2355         }
2356         for (i = 0; i < 4; i++) {
2357                 old[i].sysid = 0;
2358                 if (valid_part_table_flag(MBRbuffer)) {
2359                         if(get_part_table(i)->sys_ind) {
2360                                 old[i].sysid = get_part_table(i)->sys_ind;
2361                                 old[i].start = get_start_sect(get_part_table(i));
2362                                 old[i].nsect = get_nr_sects(get_part_table(i));
2363                                 printf(_("Trying to keep parameters of partition %d.\n"), i);
2364                                 if (debug)
2365                                         printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2366                                 old[i].sysid, old[i].start, old[i].nsect);
2367                         }
2368                 }
2369         }
2370
2371         memset(MBRbuffer, 0, sizeof(MBRbuffer));
2372         sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2373         sgilabel->boot_part = SGI_SSWAP16(0);
2374         sgilabel->swap_part = SGI_SSWAP16(1);
2375
2376         /* sizeof(sgilabel->boot_file) = 16 > 6 */
2377         memset(sgilabel->boot_file, 0, 16);
2378         strcpy((char*)sgilabel->boot_file, "/unix");
2379
2380         sgilabel->devparam.skew                     = (0);
2381         sgilabel->devparam.gap1                     = (0);
2382         sgilabel->devparam.gap2                     = (0);
2383         sgilabel->devparam.sparecyl                 = (0);
2384         sgilabel->devparam.pcylcount                = SGI_SSWAP16(geometry.cylinders);
2385         sgilabel->devparam.head_vol0                = SGI_SSWAP16(0);
2386         sgilabel->devparam.ntrks                    = SGI_SSWAP16(geometry.heads);
2387                                                 /* tracks/cylinder (heads) */
2388         sgilabel->devparam.cmd_tag_queue_depth      = (0);
2389         sgilabel->devparam.unused0                  = (0);
2390         sgilabel->devparam.unused1                  = SGI_SSWAP16(0);
2391         sgilabel->devparam.nsect                    = SGI_SSWAP16(geometry.sectors);
2392                                                 /* sectors/track */
2393         sgilabel->devparam.bytes                    = SGI_SSWAP16(512);
2394         sgilabel->devparam.ilfact                   = SGI_SSWAP16(1);
2395         sgilabel->devparam.flags                    = SGI_SSWAP32(TRACK_FWD|
2396                                                         IGNORE_ERRORS|RESEEK);
2397         sgilabel->devparam.datarate                 = SGI_SSWAP32(0);
2398         sgilabel->devparam.retries_on_error         = SGI_SSWAP32(1);
2399         sgilabel->devparam.ms_per_word              = SGI_SSWAP32(0);
2400         sgilabel->devparam.xylogics_gap1            = SGI_SSWAP16(0);
2401         sgilabel->devparam.xylogics_syncdelay       = SGI_SSWAP16(0);
2402         sgilabel->devparam.xylogics_readdelay       = SGI_SSWAP16(0);
2403         sgilabel->devparam.xylogics_gap2            = SGI_SSWAP16(0);
2404         sgilabel->devparam.xylogics_readgate        = SGI_SSWAP16(0);
2405         sgilabel->devparam.xylogics_writecont       = SGI_SSWAP16(0);
2406         memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2407         memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2408         current_label_type = label_sgi;
2409         partitions = 16;
2410         sgi_volumes = 15;
2411         sgi_set_entire();
2412         sgi_set_volhdr();
2413         for (i = 0; i < 4; i++) {
2414                 if(old[i].sysid) {
2415                         sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2416                 }
2417         }
2418 }
2419
2420 static void
2421 sgi_set_xcyl(void)
2422 {
2423         /* do nothing in the beginning */
2424 }
2425 #endif /* CONFIG_FEATURE_FDISK_ADVANCED */
2426
2427 /* _____________________________________________________________
2428  */
2429
2430 static sgiinfo *
2431 fill_sgiinfo(void)
2432 {
2433         sgiinfo *info = calloc(1, sizeof(sgiinfo));
2434
2435         info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2436         info->b1 = SGI_SSWAP32(-1);
2437         info->b2 = SGI_SSWAP16(-1);
2438         info->b3 = SGI_SSWAP16(1);
2439         /* You may want to replace this string !!!!!!! */
2440         strcpy( (char*)info->scsi_string, "IBM OEM 0662S12         3 30" );
2441         strcpy( (char*)info->serial, "0000" );
2442         info->check1816 = SGI_SSWAP16(18*256 +16 );
2443         strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2444         return info;
2445 }
2446 #endif /* SGI_LABEL */
2447
2448
2449 #ifdef CONFIG_FEATURE_SUN_LABEL
2450 /*
2451  * fdisksunlabel.c
2452  *
2453  * I think this is mostly, or entirely, due to
2454  *      Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2455  *
2456  * Merged with fdisk for other architectures, aeb, June 1998.
2457  *
2458  * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2459  *      Internationalization
2460  */
2461
2462
2463 static int sun_other_endian;
2464 static int scsi_disk;
2465 static int floppy;
2466
2467 #ifndef IDE0_MAJOR
2468 #define IDE0_MAJOR 3
2469 #endif
2470 #ifndef IDE1_MAJOR
2471 #define IDE1_MAJOR 22
2472 #endif
2473
2474 static void
2475 guess_device_type(void)
2476 {
2477         struct stat bootstat;
2478
2479         if (fstat(fd, &bootstat) < 0) {
2480                 scsi_disk = 0;
2481                 floppy = 0;
2482         } else if (S_ISBLK(bootstat.st_mode)
2483                 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2484                     major(bootstat.st_rdev) == IDE1_MAJOR)) {
2485                 scsi_disk = 0;
2486                 floppy = 0;
2487         } else if (S_ISBLK(bootstat.st_mode)
2488                 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
2489                 scsi_disk = 0;
2490                 floppy = 1;
2491         } else {
2492                 scsi_disk = 1;
2493                 floppy = 0;
2494         }
2495 }
2496
2497 static const struct systypes sun_sys_types[] = {
2498         { "\x00" "Empty"        }, /* 0            */
2499         { "\x01" "Boot"         }, /* 1            */
2500         { "\x02" "SunOS root"   }, /* 2            */
2501         { "\x03" "SunOS swap"   }, /* SUNOS_SWAP   */
2502         { "\x04" "SunOS usr"    }, /* 4            */
2503         { "\x05" "Whole disk"   }, /* WHOLE_DISK   */
2504         { "\x06" "SunOS stand"  }, /* 6            */
2505         { "\x07" "SunOS var"    }, /* 7            */
2506         { "\x08" "SunOS home"   }, /* 8            */
2507         { "\x82" "Linux swap"   }, /* LINUX_SWAP   */
2508         { "\x83" "Linux native" }, /* LINUX_NATIVE */
2509         { "\x8e" "Linux LVM"    }, /* 0x8e         */
2510 /* New (2.2.x) raid partition with autodetect using persistent superblock */
2511         { "\xfd" "Linux raid autodetect" }, /* 0xfd         */  
2512         { NULL }
2513 };
2514
2515
2516 static void
2517 set_sun_partition(int i, uint start, uint stop, int sysid)
2518 {
2519         sunlabel->infos[i].id = sysid;
2520         sunlabel->partitions[i].start_cylinder =
2521                 SUN_SSWAP32(start / (heads * sectors));
2522         sunlabel->partitions[i].num_sectors =
2523                 SUN_SSWAP32(stop - start);
2524         set_changed(i);
2525 }
2526
2527 static int
2528 check_sun_label(void)
2529 {
2530         unsigned short *ush;
2531         int csum;
2532
2533         if (sunlabel->magic != SUN_LABEL_MAGIC
2534          && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2535                 current_label_type = label_dos;
2536                 sun_other_endian = 0;
2537                 return 0;
2538         }
2539         sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2540         ush = ((unsigned short *) (sunlabel + 1)) - 1;
2541         for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2542         if (csum) {
2543                 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2544                                 "Probably you'll have to set all the values,\n"
2545                                 "e.g. heads, sectors, cylinders and partitions\n"
2546                                 "or force a fresh label (s command in main menu)\n"));
2547         } else {
2548                 heads = SUN_SSWAP16(sunlabel->ntrks);
2549                 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2550                 sectors = SUN_SSWAP16(sunlabel->nsect);
2551         }
2552         update_units();
2553         current_label_type = label_sun;
2554         partitions = 8;
2555         return 1;
2556 }
2557
2558 static const struct sun_predefined_drives {
2559         const char *vendor;
2560         const char *model;
2561         unsigned short sparecyl;
2562         unsigned short ncyl;
2563         unsigned short nacyl;
2564         unsigned short pcylcount;
2565         unsigned short ntrks;
2566         unsigned short nsect;
2567         unsigned short rspeed;
2568 } sun_drives[] = {
2569         { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2570         { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2571         { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2572         { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2573         { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2574         { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2575         { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2576         { "","SUN0104",1,974,2,1019,6,35,3662},
2577         { "","SUN0207",4,1254,2,1272,9,36,3600},
2578         { "","SUN0327",3,1545,2,1549,9,46,3600},
2579         { "","SUN0340",0,1538,2,1544,6,72,4200},
2580         { "","SUN0424",2,1151,2,2500,9,80,4400},
2581         { "","SUN0535",0,1866,2,2500,7,80,5400},
2582         { "","SUN0669",5,1614,2,1632,15,54,3600},
2583         { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2584         { "","SUN1.05",0,2036,2,2038,14,72,5400},
2585         { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2586         { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2587         { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2588 };
2589
2590 static const struct sun_predefined_drives *
2591 sun_autoconfigure_scsi(void)
2592 {
2593         const struct sun_predefined_drives *p = NULL;
2594
2595 #ifdef SCSI_IOCTL_GET_IDLUN
2596         unsigned int id[2];
2597         char buffer[2048];
2598         char buffer2[2048];
2599         FILE *pfd;
2600         char *vendor;
2601         char *model;
2602         char *q;
2603         int i;
2604
2605         if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2606                 sprintf(buffer,
2607                         "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2608 #if 0
2609                         ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2610 #else
2611                         /* This is very wrong (works only if you have one HBA),
2612                            but I haven't found a way how to get hostno
2613                            from the current kernel */
2614                         0,
2615 #endif
2616                         (id[0]>>16) & 0xff,
2617                         id[0] & 0xff,
2618                         (id[0]>>8) & 0xff
2619                 );
2620                 pfd = fopen("/proc/scsi/scsi","r");
2621                 if (pfd) {
2622                         while (fgets(buffer2, 2048, pfd)) {
2623                                 if (!strcmp(buffer, buffer2)) {
2624                                         if (fgets(buffer2,2048,pfd)) {
2625                                                 q = strstr(buffer2,"Vendor: ");
2626                                                 if (q) {
2627                                                         q += 8;
2628                                                         vendor = q;
2629                                                         q = strstr(q," ");
2630                                                         *q++ = 0;   /* truncate vendor name */
2631                                                         q = strstr(q,"Model: ");
2632                                                         if (q) {
2633                                                                 *q = 0;
2634                                                                 q += 7;
2635                                                                 model = q;
2636                                                                 q = strstr(q," Rev: ");
2637                                                                 if (q) {
2638                                                                         *q = 0;
2639                                                                         for (i = 0; i < SIZE(sun_drives); i++) {
2640                                                                                 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2641                                                                                         continue;
2642                                                                                 if (!strstr(model, sun_drives[i].model))
2643                                                                                         continue;
2644                                                                                 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2645                                                                                 p = sun_drives + i;
2646                                                                                 break;
2647                                                                         }
2648                                                                 }
2649                                                         }
2650                                                 }
2651                                         }
2652                                         break;
2653                                 }
2654                         }
2655                         fclose(pfd);
2656                 }
2657         }
2658 #endif
2659         return p;
2660 }
2661
2662 static void
2663 create_sunlabel(void)
2664 {
2665         struct hd_geometry geometry;
2666         unsigned int ndiv;
2667         int i;
2668         unsigned char c;
2669         const struct sun_predefined_drives *p = NULL;
2670
2671         fprintf(stderr,
2672                 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2673                 "until you decide to write them. After that, of course, the previous\n"
2674                 "content won't be recoverable.\n\n"));
2675         sun_other_endian = BB_LITTLE_ENDIAN;
2676         memset(MBRbuffer, 0, sizeof(MBRbuffer));
2677         sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2678         if (!floppy) {
2679                 puts(_("Drive type\n"
2680                  "   ?   auto configure\n"
2681                  "   0   custom (with hardware detected defaults)"));
2682                 for (i = 0; i < SIZE(sun_drives); i++) {
2683                         printf("   %c   %s%s%s\n",
2684                                 i + 'a', sun_drives[i].vendor,
2685                                 (*sun_drives[i].vendor) ? " " : "",
2686                                 sun_drives[i].model);
2687                 }
2688                 while (1) {
2689                         c = read_char(_("Select type (? for auto, 0 for custom): "));
2690                         if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2691                                 p = sun_drives + c - 'a';
2692                                 break;
2693                         } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2694                                 p = sun_drives + c - 'A';
2695                                 break;
2696                         } else if (c == '0') {
2697                                 break;
2698                         } else if (c == '?' && scsi_disk) {
2699                                 p = sun_autoconfigure_scsi();
2700                                 if (!p)
2701                                 printf(_("Autoconfigure failed.\n"));
2702                                 else
2703                                 break;
2704                         }
2705                 }
2706         }
2707         if (!p || floppy) {
2708                 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2709                         heads = geometry.heads;
2710                         sectors = geometry.sectors;
2711                         cylinders = geometry.cylinders;
2712                 } else {
2713                         heads = 0;
2714                         sectors = 0;
2715                         cylinders = 0;
2716                 }
2717                 if (floppy) {
2718                         sunlabel->nacyl = 0;
2719                         sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2720                         sunlabel->rspeed = SUN_SSWAP16(300);
2721                         sunlabel->ilfact = SUN_SSWAP16(1);
2722                         sunlabel->sparecyl = 0;
2723                 } else {
2724                         heads = read_int(1,heads,1024,0,_("Heads"));
2725                         sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2726                 if (cylinders)
2727                         cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2728                 else
2729                         cylinders = read_int(1,0,65535,0,_("Cylinders"));
2730                         sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2731                         sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2732                         sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2733                         sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2734                         sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2735                 }
2736         } else {
2737                 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2738                 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2739                 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2740                 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2741                 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2742                 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2743                 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2744                 sunlabel->ilfact = SUN_SSWAP16(1);
2745                 cylinders = p->ncyl;
2746                 heads = p->ntrks;
2747                 sectors = p->nsect;
2748                 puts(_("You may change all the disk params from the x menu"));
2749         }
2750
2751         snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
2752                 "%s%s%s cyl %d alt %d hd %d sec %d",
2753                 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2754                 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2755                 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2756
2757         sunlabel->ntrks = SUN_SSWAP16(heads);
2758         sunlabel->nsect = SUN_SSWAP16(sectors);
2759         sunlabel->ncyl = SUN_SSWAP16(cylinders);
2760         if (floppy)
2761                 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2762         else {
2763                 if (cylinders * heads * sectors >= 150 * 2048) {
2764                         ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2765                 } else
2766                         ndiv = cylinders * 2 / 3;
2767                 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2768                 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2769                 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2770         }
2771         set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2772         {
2773                 unsigned short *ush = (unsigned short *)sunlabel;
2774                 unsigned short csum = 0;
2775                 while (ush < (unsigned short *)(&sunlabel->csum))
2776                         csum ^= *ush++;
2777                 sunlabel->csum = csum;
2778         }
2779
2780         set_all_unchanged();
2781         set_changed(0);
2782         get_boot(create_empty_sun);
2783 }
2784
2785 static void
2786 toggle_sunflags(int i, unsigned char mask)
2787 {
2788         if (sunlabel->infos[i].flags & mask)
2789                 sunlabel->infos[i].flags &= ~mask;
2790         else
2791                 sunlabel->infos[i].flags |= mask;
2792         set_changed(i);
2793 }
2794
2795 static void
2796 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2797 {
2798         int i, continuous = 1;
2799
2800         *start = 0;
2801         *stop = cylinders * heads * sectors;
2802         for (i = 0; i < partitions; i++) {
2803                 if (sunlabel->partitions[i].num_sectors
2804                  && sunlabel->infos[i].id
2805                  && sunlabel->infos[i].id != WHOLE_DISK) {
2806                         starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2807                         lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2808                         if (continuous) {
2809                                 if (starts[i] == *start)
2810                                         *start += lens[i];
2811                                 else if (starts[i] + lens[i] >= *stop)
2812                                         *stop = starts[i];
2813                                 else
2814                                         continuous = 0;
2815                                         /* There will be probably more gaps
2816                                           than one, so lets check afterwards */
2817                         }
2818                 } else {
2819                         starts[i] = 0;
2820                         lens[i] = 0;
2821                 }
2822         }
2823 }
2824
2825 static uint *verify_sun_starts;
2826
2827 static int
2828 verify_sun_cmp(int *a, int *b)
2829 {
2830         if (*a == -1) return 1;
2831         if (*b == -1) return -1;
2832         if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2833         return -1;
2834 }
2835
2836 static void
2837 verify_sun(void)
2838 {
2839         uint starts[8], lens[8], start, stop;
2840         int i,j,k,starto,endo;
2841         int array[8];
2842
2843         verify_sun_starts = starts;
2844         fetch_sun(starts,lens,&start,&stop);
2845         for (k = 0; k < 7; k++) {
2846                 for (i = 0; i < 8; i++) {
2847                         if (k && (lens[i] % (heads * sectors))) {
2848                                 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2849                         }
2850                         if (lens[i]) {
2851                                 for (j = 0; j < i; j++)
2852                                         if (lens[j]) {
2853                                                 if (starts[j] == starts[i]+lens[i]) {
2854                                                         starts[j] = starts[i]; lens[j] += lens[i];
2855                                                         lens[i] = 0;
2856                                                 } else if (starts[i] == starts[j]+lens[j]){
2857                                                         lens[j] += lens[i];
2858                                                         lens[i] = 0;
2859                                                 } else if (!k) {
2860                                                         if (starts[i] < starts[j]+lens[j]
2861                                                          && starts[j] < starts[i]+lens[i]) {
2862                                                                 starto = starts[i];
2863                                                                 if (starts[j] > starto)
2864                                                                         starto = starts[j];
2865                                                                 endo = starts[i]+lens[i];
2866                                                                 if (starts[j]+lens[j] < endo)
2867                                                                         endo = starts[j]+lens[j];
2868                                                                 printf(_("Partition %d overlaps with others in "
2869                                                                         "sectors %d-%d\n"), i+1, starto, endo);
2870                                                         }
2871                                                 }
2872                                         }
2873                         }
2874                 }
2875         }
2876         for (i = 0; i < 8; i++) {
2877                 if (lens[i])
2878                         array[i] = i;
2879                 else
2880                         array[i] = -1;
2881         }
2882         qsort(array,SIZE(array),sizeof(array[0]),
2883                 (int (*)(const void *,const void *)) verify_sun_cmp);
2884         if (array[0] == -1) {
2885                 printf(_("No partitions defined\n"));
2886                 return;
2887         }
2888         stop = cylinders * heads * sectors;
2889         if (starts[array[0]])
2890                 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2891         for (i = 0; i < 7 && array[i+1] != -1; i++) {
2892                 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2893         }
2894         start = starts[array[i]] + lens[array[i]];
2895         if (start < stop)
2896                 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2897 }
2898
2899 static void
2900 add_sun_partition(int n, int sys)
2901 {
2902         uint start, stop, stop2;
2903         uint starts[8], lens[8];
2904         int whole_disk = 0;
2905
2906         char mesg[256];
2907         int i, first, last;
2908
2909         if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2910                 printf(_("Partition %d is already defined.  Delete "
2911                         "it before re-adding it.\n"), n + 1);
2912                 return;
2913         }
2914
2915         fetch_sun(starts,lens,&start,&stop);
2916         if (stop <= start) {
2917                 if (n == 2)
2918                         whole_disk = 1;
2919                 else {
2920                         printf(_("Other partitions already cover the whole disk.\nDelete "
2921                                    "some/shrink them before retry.\n"));
2922                         return;
2923                 }
2924         }
2925         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2926         while (1) {
2927                 if (whole_disk)
2928                         first = read_int(0, 0, 0, 0, mesg);
2929                 else
2930                         first = read_int(scround(start), scround(stop)+1,
2931                                          scround(stop), 0, mesg);
2932                 if (display_in_cyl_units)
2933                         first *= units_per_sector;
2934                 else
2935                         /* Starting sector has to be properly aligned */
2936                         first = (first + heads * sectors - 1) / (heads * sectors);
2937                 if (n == 2 && first != 0)
2938                         printf("\
2939 It is highly recommended that the third partition covers the whole disk\n\
2940 and is of type `Whole disk'\n");
2941                 /* ewt asks to add: "don't start a partition at cyl 0"
2942                    However, edmundo@rano.demon.co.uk writes:
2943                    "In addition to having a Sun partition table, to be able to
2944                    boot from the disc, the first partition, /dev/sdX1, must
2945                    start at cylinder 0. This means that /dev/sdX1 contains
2946                    the partition table and the boot block, as these are the
2947                    first two sectors of the disc. Therefore you must be
2948                    careful what you use /dev/sdX1 for. In particular, you must
2949                    not use a partition starting at cylinder 0 for Linux swap,
2950                    as that would overwrite the partition table and the boot
2951                    block. You may, however, use such a partition for a UFS
2952                    or EXT2 file system, as these file systems leave the first
2953                    1024 bytes undisturbed. */
2954                 /* On the other hand, one should not use partitions
2955                    starting at block 0 in an md, or the label will
2956                    be trashed. */
2957                 for (i = 0; i < partitions; i++)
2958                         if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
2959                                 break;
2960                 if (i < partitions && !whole_disk) {
2961                         if (n == 2 && !first) {
2962                                 whole_disk = 1;
2963                                 break;
2964                         }
2965                         printf(_("Sector %d is already allocated\n"), first);
2966                 } else
2967                         break;
2968         }
2969         stop = cylinders * heads * sectors;
2970         stop2 = stop;
2971         for (i = 0; i < partitions; i++) {
2972                 if (starts[i] > first && starts[i] < stop)
2973                         stop = starts[i];
2974         }
2975         snprintf(mesg, sizeof(mesg),
2976                 _("Last %s or +size or +sizeM or +sizeK"),
2977                 str_units(SINGULAR));
2978         if (whole_disk)
2979                 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2980                                 0, mesg);
2981         else if (n == 2 && !first)
2982                 last = read_int(scround(first), scround(stop2), scround(stop2),
2983                                 scround(first), mesg);
2984         else
2985                 last = read_int(scround(first), scround(stop), scround(stop),
2986                                 scround(first), mesg);
2987         if (display_in_cyl_units)
2988                 last *= units_per_sector;
2989         if (n == 2 && !first) {
2990                 if (last >= stop2) {
2991                         whole_disk = 1;
2992                         last = stop2;
2993                 } else if (last > stop) {
2994                         printf(_("You haven't covered the whole disk with "
2995                                 "the 3rd partition, but your value\n"
2996                                 "%d %s covers some other partition. "
2997                                 "Your entry has been changed\n"
2998                                 "to %d %s\n"),
2999                                 scround(last), str_units(SINGULAR),
3000                                 scround(stop), str_units(SINGULAR));
3001                         last = stop;
3002                 }
3003         } else if (!whole_disk && last > stop)
3004                 last = stop;
3005
3006         if (whole_disk)
3007                 sys = WHOLE_DISK;
3008         set_sun_partition(n, first, last, sys);
3009 }
3010
3011 static void
3012 sun_delete_partition(int i)
3013 {
3014         unsigned int nsec;
3015
3016         if (i == 2
3017          && sunlabel->infos[i].id == WHOLE_DISK
3018          && !sunlabel->partitions[i].start_cylinder
3019          && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
3020                 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3021                         "consider leaving this\n"
3022                         "partition as Whole disk (5), starting at 0, with %u "
3023                         "sectors\n"), nsec);
3024         sunlabel->infos[i].id = 0;
3025         sunlabel->partitions[i].num_sectors = 0;
3026 }
3027
3028 static void
3029 sun_change_sysid(int i, int sys)
3030 {
3031         if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3032                 read_chars(
3033                         _("It is highly recommended that the partition at offset 0\n"
3034                         "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3035                         "there may destroy your partition table and bootblock.\n"
3036                         "Type YES if you're very sure you would like that partition\n"
3037                         "tagged with 82 (Linux swap): "));
3038                 if (strcmp (line_ptr, _("YES\n")))
3039                         return;
3040         }
3041         switch (sys) {
3042         case SUNOS_SWAP:
3043         case LINUX_SWAP:
3044                 /* swaps are not mountable by default */
3045                 sunlabel->infos[i].flags |= 0x01;
3046                 break;
3047         default:
3048                 /* assume other types are mountable;
3049                    user can change it anyway */
3050                 sunlabel->infos[i].flags &= ~0x01;
3051                 break;
3052         }
3053         sunlabel->infos[i].id = sys;
3054 }
3055
3056 static void
3057 sun_list_table(int xtra)
3058 {
3059         int i, w;
3060
3061         w = strlen(disk_device);
3062         if (xtra)
3063                 printf(
3064                 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3065                 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3066                 "%d extra sects/cyl, interleave %d:1\n"
3067                 "%s\n"
3068                 "Units = %s of %d * 512 bytes\n\n"),
3069                         disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3070                         cylinders, SUN_SSWAP16(sunlabel->nacyl),
3071                         SUN_SSWAP16(sunlabel->pcylcount),
3072                         SUN_SSWAP16(sunlabel->sparecyl),
3073                         SUN_SSWAP16(sunlabel->ilfact),
3074                         (char *)sunlabel,
3075                         str_units(PLURAL), units_per_sector);
3076         else
3077                 printf(
3078         _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3079         "Units = %s of %d * 512 bytes\n\n"),
3080                         disk_device, heads, sectors, cylinders,
3081                         str_units(PLURAL), units_per_sector);
3082
3083         printf(_("%*s Flag    Start       End    Blocks   Id  System\n"),
3084                 w + 1, _("Device"));
3085         for (i = 0 ; i < partitions; i++) {
3086                 if (sunlabel->partitions[i].num_sectors) {
3087                         uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3088                         uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
3089                         printf("%s %c%c %9ld %9ld %9ld%c  %2x  %s\n",
3090                                 partname(disk_device, i+1, w),                  /* device */            
3091                                 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',  /* flags */             
3092                                 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',                          
3093                                 (long) scround(start),                          /* start */             
3094                                 (long) scround(start+len),                      /* end */               
3095                                 (long) len / 2, len & 1 ? '+' : ' ',            /* odd flag on end */   
3096                                 sunlabel->infos[i].id,                          /* type id */           
3097                                 partition_type(sunlabel->infos[i].id));         /* type name */         
3098                 }
3099         }
3100 }
3101
3102 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3103
3104 static void
3105 sun_set_alt_cyl(void)
3106 {
3107         sunlabel->nacyl =
3108                 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3109                                 _("Number of alternate cylinders")));
3110 }
3111
3112 static void
3113 sun_set_ncyl(int cyl)
3114 {
3115         sunlabel->ncyl = SUN_SSWAP16(cyl);
3116 }
3117
3118 static void
3119 sun_set_xcyl(void)
3120 {
3121         sunlabel->sparecyl =
3122                 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3123                                 _("Extra sectors per cylinder")));
3124 }
3125
3126 static void
3127 sun_set_ilfact(void)
3128 {
3129         sunlabel->ilfact =
3130                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3131                                 _("Interleave factor")));
3132 }
3133
3134 static void
3135 sun_set_rspeed(void)
3136 {
3137         sunlabel->rspeed =
3138                 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3139                                 _("Rotation speed (rpm)")));
3140 }
3141
3142 static void
3143 sun_set_pcylcount(void)
3144 {
3145         sunlabel->pcylcount =
3146                 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3147                                 _("Number of physical cylinders")));
3148 }
3149 #endif /* CONFIG_FEATURE_FDISK_ADVANCED */
3150
3151 static void
3152 sun_write_table(void)
3153 {
3154         unsigned short *ush = (unsigned short *)sunlabel;
3155         unsigned short csum = 0;
3156
3157         while (ush < (unsigned short *)(&sunlabel->csum))
3158                 csum ^= *ush++;
3159         sunlabel->csum = csum;
3160         if (lseek(fd, 0, SEEK_SET) < 0)
3161                 fdisk_fatal(unable_to_seek);
3162         if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3163                 fdisk_fatal(unable_to_write);
3164 }
3165 #endif /* SUN_LABEL */
3166
3167 /* DOS partition types */
3168
3169 static const struct systypes i386_sys_types[] = {
3170         { "\x00" "Empty" },
3171         { "\x01" "FAT12" },
3172         { "\x04" "FAT16 <32M" },
3173         { "\x05" "Extended" },         /* DOS 3.3+ extended partition */
3174         { "\x06" "FAT16" },            /* DOS 16-bit >=32M */
3175         { "\x07" "HPFS/NTFS" },        /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3176         { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3177         { "\x0b" "Win95 FAT32" },
3178         { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3179         { "\x0e" "Win95 FAT16 (LBA)" },
3180         { "\x0f" "Win95 Ext'd (LBA)" },
3181         { "\x11" "Hidden FAT12" },
3182         { "\x12" "Compaq diagnostics" },
3183         { "\x14" "Hidden FAT16 <32M" },
3184         { "\x16" "Hidden FAT16" },
3185         { "\x17" "Hidden HPFS/NTFS" },
3186         { "\x1b" "Hidden Win95 FAT32" },
3187         { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3188         { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3189         { "\x3c" "PartitionMagic recovery" },
3190         { "\x41" "PPC PReP Boot" },
3191         { "\x42" "SFS" },
3192         { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3193         { "\x80" "Old Minix" },        /* Minix 1.4a and earlier */
3194         { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3195         { "\x82" "Linux swap" },       /* also Solaris */
3196         { "\x83" "Linux" },
3197         { "\x84" "OS/2 hidden C: drive" },
3198         { "\x85" "Linux extended" },
3199         { "\x86" "NTFS volume set" },
3200         { "\x87" "NTFS volume set" },
3201         { "\x8e" "Linux LVM" },
3202         { "\x9f" "BSD/OS" },           /* BSDI */
3203         { "\xa0" "IBM Thinkpad hibernation" },
3204         { "\xa5" "FreeBSD" },          /* various BSD flavours */
3205         { "\xa6" "OpenBSD" },
3206         { "\xa8" "Darwin UFS" },
3207         { "\xa9" "NetBSD" },
3208         { "\xab" "Darwin boot" },
3209         { "\xb7" "BSDI fs" },
3210         { "\xb8" "BSDI swap" },
3211         { "\xbe" "Solaris boot" },
3212         { "\xeb" "BeOS fs" },
3213         { "\xee" "EFI GPT" },          /* Intel EFI GUID Partition Table */
3214         { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3215         { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3216         { "\xf2" "DOS secondary" },    /* DOS 3.3+ secondary */
3217         { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3218                                                 autodetect using persistent
3219                                                 superblock */
3220 #ifdef CONFIG_WEIRD_PARTITION_TYPES
3221         { "\x02" "XENIX root" },
3222         { "\x03" "XENIX usr" },
3223         { "\x08" "AIX" },              /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3224         { "\x09" "AIX bootable" },     /* AIX data or Coherent */
3225         { "\x10" "OPUS" },
3226         { "\x18" "AST SmartSleep" },
3227         { "\x24" "NEC DOS" },
3228         { "\x39" "Plan 9" },
3229         { "\x40" "Venix 80286" },
3230         { "\x4d" "QNX4.x" },
3231         { "\x4e" "QNX4.x 2nd part" },
3232         { "\x4f" "QNX4.x 3rd part" },
3233         { "\x50" "OnTrack DM" },
3234         { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3235         { "\x52" "CP/M" },             /* CP/M or Microport SysV/AT */
3236         { "\x53" "OnTrack DM6 Aux3" },
3237         { "\x54" "OnTrackDM6" },
3238         { "\x55" "EZ-Drive" },
3239         { "\x56" "Golden Bow" },
3240         { "\x5c" "Priam Edisk" },
3241         { "\x61" "SpeedStor" },
3242         { "\x64" "Novell Netware 286" },
3243         { "\x65" "Novell Netware 386" },
3244         { "\x70" "DiskSecure Multi-Boot" },
3245         { "\x75" "PC/IX" },
3246         { "\x93" "Amoeba" },
3247         { "\x94" "Amoeba BBT" },       /* (bad block table) */
3248         { "\xa7" "NeXTSTEP" },
3249         { "\xbb" "Boot Wizard hidden" },
3250         { "\xc1" "DRDOS/sec (FAT-12)" },
3251         { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3252         { "\xc6" "DRDOS/sec (FAT-16)" },
3253         { "\xc7" "Syrinx" },
3254         { "\xda" "Non-FS data" },
3255         { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
3256                                         Concurrent DOS or CTOS */
3257         { "\xde" "Dell Utility" },     /* Dell PowerEdge Server utilities */
3258         { "\xdf" "BootIt" },           /* BootIt EMBRM */
3259         { "\xe1" "DOS access" },       /* DOS access or SpeedStor 12-bit FAT
3260                                         extended partition */
3261         { "\xe3" "DOS R/O" },          /* DOS R/O or SpeedStor */
3262         { "\xe4" "SpeedStor" },        /* SpeedStor 16-bit FAT extended
3263                                         partition < 1024 cyl. */
3264         { "\xf1" "SpeedStor" },
3265         { "\xf4" "SpeedStor" },        /* SpeedStor large partition */
3266         { "\xfe" "LANstep" },          /* SpeedStor >1024 cyl. or LANstep */
3267         { "\xff" "BBT" },              /* Xenix Bad Block Table */
3268 #endif
3269         { 0 }
3270 };
3271
3272
3273
3274 /* A valid partition table sector ends in 0x55 0xaa */
3275 static unsigned int
3276 part_table_flag(const char *b)
3277 {
3278         return ((uint) b[510]) + (((uint) b[511]) << 8);
3279 }
3280
3281
3282 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3283 static void
3284 write_part_table_flag(char *b)
3285 {
3286         b[510] = 0x55;
3287         b[511] = 0xaa;
3288 }
3289
3290 /* start_sect and nr_sects are stored little endian on all machines */
3291 /* moreover, they are not aligned correctly */
3292 static void
3293 store4_little_endian(unsigned char *cp, unsigned int val)
3294 {
3295         cp[0] = (val & 0xff);
3296         cp[1] = ((val >> 8) & 0xff);
3297         cp[2] = ((val >> 16) & 0xff);
3298         cp[3] = ((val >> 24) & 0xff);
3299 }
3300 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3301
3302 static unsigned int
3303 read4_little_endian(const unsigned char *cp)
3304 {
3305         return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3306                 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3307 }
3308
3309 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3310 static void
3311 set_start_sect(struct partition *p, unsigned int start_sect)
3312 {
3313         store4_little_endian(p->start4, start_sect);
3314 }
3315 #endif
3316
3317 static int32_t
3318 get_start_sect(const struct partition *p)
3319 {
3320         return read4_little_endian(p->start4);
3321 }
3322
3323 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3324 static void
3325 set_nr_sects(struct partition *p, int32_t nr_sects)
3326 {
3327         store4_little_endian(p->size4, nr_sects);
3328 }
3329 #endif
3330
3331 static int32_t
3332 get_nr_sects(const struct partition *p)
3333 {
3334         return read4_little_endian(p->size4);
3335 }
3336
3337 /* normally O_RDWR, -l option gives O_RDONLY */
3338 static int type_open = O_RDWR;
3339
3340
3341 static int ext_index;               /* the prime extended partition */
3342 static int listing;                    /* no aborts for fdisk -l */
3343 static int dos_compatible_flag = ~0;
3344 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3345 static int dos_changed;
3346 static int nowarn;            /* no warnings for fdisk -l/-s */
3347 #endif
3348
3349
3350
3351 static uint user_cylinders, user_heads, user_sectors;
3352 static uint pt_heads, pt_sectors;
3353 static uint kern_heads, kern_sectors;
3354
3355 static off_t extended_offset;            /* offset of link pointers */
3356
3357 static unsigned long long total_number_of_sectors;
3358
3359
3360 static jmp_buf listingbuf;
3361
3362 static void fdisk_fatal(enum failure why)
3363 {
3364         const char *message;
3365
3366         if (listing) {
3367                 close(fd);
3368                 longjmp(listingbuf, 1);
3369         }
3370
3371         switch (why) {
3372         case unable_to_open:
3373                 message = "Unable to open %s\n";
3374                 break;
3375         case unable_to_read:
3376                 message = "Unable to read %s\n";
3377                 break;
3378         case unable_to_seek:
3379                 message = "Unable to seek on %s\n";
3380                 break;
3381         case unable_to_write:
3382                 message = "Unable to write %s\n";
3383                 break;
3384         case ioctl_error:
3385                 message = "BLKGETSIZE ioctl failed on %s\n";
3386                 break;
3387         default:
3388                 message = "Fatal error\n";
3389         }
3390
3391         fputc('\n', stderr);
3392         fprintf(stderr, message, disk_device);
3393         exit(1);
3394 }
3395
3396 static void
3397 seek_sector(off_t secno)
3398 {
3399         off_t offset = secno * sector_size;
3400         if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
3401                 fdisk_fatal(unable_to_seek);
3402 }
3403
3404 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3405 static void
3406 write_sector(off_t secno, char *buf)
3407 {
3408         seek_sector(secno);
3409         if (write(fd, buf, sector_size) != sector_size)
3410                 fdisk_fatal(unable_to_write);
3411 }
3412 #endif
3413
3414 /* Allocate a buffer and read a partition table sector */
3415 static void
3416 read_pte(struct pte *pe, off_t offset)
3417 {
3418         pe->offset = offset;
3419         pe->sectorbuffer = (char *) xmalloc(sector_size);
3420         seek_sector(offset);
3421         if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3422                 fdisk_fatal(unable_to_read);
3423 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3424         pe->changed = 0;
3425 #endif
3426         pe->part_table = pe->ext_pointer = NULL;
3427 }
3428
3429 static unsigned int
3430 get_partition_start(const struct pte *pe)
3431 {
3432         return pe->offset + get_start_sect(pe->part_table);
3433 }
3434
3435 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3436 /*
3437  * Avoid warning about DOS partitions when no DOS partition was changed.
3438  * Here a heuristic "is probably dos partition".
3439  * We might also do the opposite and warn in all cases except
3440  * for "is probably nondos partition".
3441  */
3442 static int
3443 is_dos_partition(int t)
3444 {
3445         return (t == 1 || t == 4 || t == 6 ||
3446                 t == 0x0b || t == 0x0c || t == 0x0e ||
3447                 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3448                 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3449                 t == 0xc1 || t == 0xc4 || t == 0xc6);
3450 }
3451
3452 static void
3453 menu(void)
3454 {
3455 #ifdef CONFIG_FEATURE_SUN_LABEL
3456         if (label_sun == current_label_type) {
3457                 puts(_("Command action"));
3458                 puts(_("\ta\ttoggle a read only flag"));           /* sun */
3459                 puts(_("\tb\tedit bsd disklabel"));
3460                 puts(_("\tc\ttoggle the mountable flag"));         /* sun */
3461                 puts(_("\td\tdelete a partition"));
3462                 puts(_("\tl\tlist known partition types"));
3463                 puts(_("\tm\tprint this menu"));
3464                 puts(_("\tn\tadd a new partition"));
3465                 puts(_("\to\tcreate a new empty DOS partition table"));
3466                 puts(_("\tp\tprint the partition table"));
3467                 puts(_("\tq\tquit without saving changes"));
3468                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3469                 puts(_("\tt\tchange a partition's system id"));
3470                 puts(_("\tu\tchange display/entry units"));
3471                 puts(_("\tv\tverify the partition table"));
3472                 puts(_("\tw\twrite table to disk and exit"));
3473 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3474                 puts(_("\tx\textra functionality (experts only)"));
3475 #endif
3476         } else
3477 #endif
3478 #ifdef CONFIG_FEATURE_SGI_LABEL
3479         if (label_sgi == current_label_type) {
3480                 puts(_("Command action"));
3481                 puts(_("\ta\tselect bootable partition"));    /* sgi flavour */
3482                 puts(_("\tb\tedit bootfile entry"));          /* sgi */
3483                 puts(_("\tc\tselect sgi swap partition"));    /* sgi flavour */
3484                 puts(_("\td\tdelete a partition"));
3485                 puts(_("\tl\tlist known partition types"));
3486                 puts(_("\tm\tprint this menu"));
3487                 puts(_("\tn\tadd a new partition"));
3488                 puts(_("\to\tcreate a new empty DOS partition table"));
3489                 puts(_("\tp\tprint the partition table"));
3490                 puts(_("\tq\tquit without saving changes"));
3491                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3492                 puts(_("\tt\tchange a partition's system id"));
3493                 puts(_("\tu\tchange display/entry units"));
3494                 puts(_("\tv\tverify the partition table"));
3495                 puts(_("\tw\twrite table to disk and exit"));
3496         } else
3497 #endif
3498 #ifdef CONFIG_FEATURE_AIX_LABEL
3499         if (label_aix == current_label_type) {
3500                 puts(_("Command action"));
3501                 puts(_("\tm\tprint this menu"));
3502                 puts(_("\to\tcreate a new empty DOS partition table"));
3503                 puts(_("\tq\tquit without saving changes"));
3504                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3505         } else
3506 #endif
3507         {
3508                 puts(_("Command action"));
3509                 puts(_("\ta\ttoggle a bootable flag"));
3510                 puts(_("\tb\tedit bsd disklabel"));
3511                 puts(_("\tc\ttoggle the dos compatibility flag"));
3512                 puts(_("\td\tdelete a partition"));
3513                 puts(_("\tl\tlist known partition types"));
3514                 puts(_("\tm\tprint this menu"));
3515                 puts(_("\tn\tadd a new partition"));
3516                 puts(_("\to\tcreate a new empty DOS partition table"));
3517                 puts(_("\tp\tprint the partition table"));
3518                 puts(_("\tq\tquit without saving changes"));
3519                 puts(_("\ts\tcreate a new empty Sun disklabel"));  /* sun */
3520                 puts(_("\tt\tchange a partition's system id"));
3521                 puts(_("\tu\tchange display/entry units"));
3522                 puts(_("\tv\tverify the partition table"));
3523                 puts(_("\tw\twrite table to disk and exit"));
3524 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3525                 puts(_("\tx\textra functionality (experts only)"));
3526 #endif
3527         }
3528 }
3529 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3530
3531
3532 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
3533 static void
3534 xmenu(void)
3535 {
3536 #ifdef CONFIG_FEATURE_SUN_LABEL
3537         if (label_sun == current_label_type) {
3538         puts(_("Command action"));
3539         puts(_("\ta\tchange number of alternate cylinders"));      /*sun*/
3540         puts(_("\tc\tchange number of cylinders"));
3541         puts(_("\td\tprint the raw data in the partition table"));
3542         puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3543         puts(_("\th\tchange number of heads"));
3544         puts(_("\ti\tchange interleave factor"));                  /*sun*/
3545         puts(_("\to\tchange rotation speed (rpm)"));               /*sun*/
3546         puts(_("\tm\tprint this menu"));
3547         puts(_("\tp\tprint the partition table"));
3548         puts(_("\tq\tquit without saving changes"));
3549         puts(_("\tr\treturn to main menu"));
3550         puts(_("\ts\tchange number of sectors/track"));
3551         puts(_("\tv\tverify the partition table"));
3552         puts(_("\tw\twrite table to disk and exit"));
3553         puts(_("\ty\tchange number of physical cylinders"));       /*sun*/
3554         }  else
3555 #endif
3556 #ifdef CONFIG_FEATURE_SGI_LABEL
3557         if (label_sgi == current_label_type) {
3558                 puts(_("Command action"));
3559                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3560                 puts(_("\tc\tchange number of cylinders"));
3561                 puts(_("\td\tprint the raw data in the partition table"));
3562                 puts(_("\te\tlist extended partitions"));          /* !sun */
3563                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3564                 puts(_("\th\tchange number of heads"));
3565                 puts(_("\tm\tprint this menu"));
3566                 puts(_("\tp\tprint the partition table"));
3567                 puts(_("\tq\tquit without saving changes"));
3568                 puts(_("\tr\treturn to main menu"));
3569                 puts(_("\ts\tchange number of sectors/track"));
3570                 puts(_("\tv\tverify the partition table"));
3571                 puts(_("\tw\twrite table to disk and exit"));
3572         } else
3573 #endif
3574 #ifdef CONFIG_FEATURE_AIX_LABEL
3575         if (label_aix == current_label_type) {
3576                 puts(_("Command action"));
3577                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3578                 puts(_("\tc\tchange number of cylinders"));
3579                 puts(_("\td\tprint the raw data in the partition table"));
3580                 puts(_("\te\tlist extended partitions"));          /* !sun */
3581                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3582                 puts(_("\th\tchange number of heads"));
3583                 puts(_("\tm\tprint this menu"));
3584                 puts(_("\tp\tprint the partition table"));
3585                 puts(_("\tq\tquit without saving changes"));
3586                 puts(_("\tr\treturn to main menu"));
3587                 puts(_("\ts\tchange number of sectors/track"));
3588                 puts(_("\tv\tverify the partition table"));
3589                 puts(_("\tw\twrite table to disk and exit"));
3590         }  else
3591 #endif
3592         {
3593                 puts(_("Command action"));
3594                 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3595                 puts(_("\tc\tchange number of cylinders"));
3596                 puts(_("\td\tprint the raw data in the partition table"));
3597                 puts(_("\te\tlist extended partitions"));          /* !sun */
3598                 puts(_("\tf\tfix partition order"));               /* !sun, !aix, !sgi */
3599 #ifdef CONFIG_FEATURE_SGI_LABEL
3600                 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3601 #endif
3602                 puts(_("\th\tchange number of heads"));
3603                 puts(_("\tm\tprint this menu"));
3604                 puts(_("\tp\tprint the partition table"));
3605                 puts(_("\tq\tquit without saving changes"));
3606                 puts(_("\tr\treturn to main menu"));
3607                 puts(_("\ts\tchange number of sectors/track"));
3608                 puts(_("\tv\tverify the partition table"));
3609                 puts(_("\tw\twrite table to disk and exit"));
3610         }
3611 }
3612 #endif /* ADVANCED mode */
3613
3614 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3615 static const struct systypes *
3616 get_sys_types(void)
3617 {
3618         return (
3619 #ifdef CONFIG_FEATURE_SUN_LABEL
3620                 label_sun == current_label_type ? sun_sys_types :
3621 #endif
3622 #ifdef CONFIG_FEATURE_SGI_LABEL
3623                 label_sgi == current_label_type ? sgi_sys_types :
3624 #endif
3625                 i386_sys_types);
3626 }
3627 #else
3628 #define get_sys_types() i386_sys_types
3629 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3630
3631 static const char *partition_type(unsigned char type)
3632 {
3633         int i;
3634         const struct systypes *types = get_sys_types();
3635
3636         for (i = 0; types[i].name; i++)
3637                 if ((unsigned char )types[i].name[0] == type)
3638                         return types[i].name + 1;
3639
3640         return _("Unknown");
3641 }
3642
3643
3644 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3645 static int
3646 get_sysid(int i)
3647 {
3648         return (
3649 #ifdef CONFIG_FEATURE_SUN_LABEL
3650                 label_sun == current_label_type ? sunlabel->infos[i].id :
3651 #endif
3652 #ifdef CONFIG_FEATURE_SGI_LABEL
3653                 label_sgi == current_label_type ? sgi_get_sysid(i) :
3654 #endif
3655                 ptes[i].part_table->sys_ind);
3656 }
3657
3658 void list_types(const struct systypes *sys)
3659 {
3660         uint last[4], done = 0, next = 0, size;
3661         int i;
3662
3663         for (i = 0; sys[i].name; i++);
3664         size = i;
3665
3666         for (i = 3; i >= 0; i--)
3667                 last[3 - i] = done += (size + i - done) / (i + 1);
3668         i = done = 0;
3669
3670         do {
3671                 printf("%c%2x  %-15.15s", i ? ' ' : '\n',
3672                         (unsigned char)sys[next].name[0],
3673                         partition_type((unsigned char)sys[next].name[0]));
3674                 next = last[i++] + done;
3675                 if (i > 3 || next >= last[i]) {
3676                         i = 0;
3677                         next = ++done;
3678                 }
3679         } while (done < last[0]);
3680         putchar('\n');
3681 }
3682 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3683
3684 static int
3685 is_cleared_partition(const struct partition *p)
3686 {
3687         return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3688                  p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3689                  get_start_sect(p) || get_nr_sects(p));
3690 }
3691
3692 static void
3693 clear_partition(struct partition *p)
3694 {
3695         if (!p)
3696                 return;
3697         memset(p, 0, sizeof(struct partition));
3698 }
3699
3700 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3701 static void
3702 set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3703 {
3704         struct partition *p;
3705         off_t offset;
3706
3707         if (doext) {
3708                 p = ptes[i].ext_pointer;
3709                 offset = extended_offset;
3710         } else {
3711                 p = ptes[i].part_table;
3712                 offset = ptes[i].offset;
3713         }
3714         p->boot_ind = 0;
3715         p->sys_ind = sysid;
3716         set_start_sect(p, start - offset);
3717         set_nr_sects(p, stop - start + 1);
3718         if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3719                 start = heads*sectors*1024 - 1;
3720         set_hsc(p->head, p->sector, p->cyl, start);
3721         if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3722                 stop = heads*sectors*1024 - 1;
3723         set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3724         ptes[i].changed = 1;
3725 }
3726 #endif
3727
3728 static int
3729 test_c(const char **m, const char *mesg)
3730 {
3731         int val = 0;
3732         if (!*m)
3733                 fprintf(stderr, _("You must set"));
3734         else {
3735                 fprintf(stderr, " %s", *m);
3736                 val = 1;
3737         }
3738         *m = mesg;
3739         return val;
3740 }
3741
3742 static int
3743 warn_geometry(void)
3744 {
3745         const char *m = NULL;
3746         int prev = 0;
3747
3748         if (!heads)
3749                 prev = test_c(&m, _("heads"));
3750         if (!sectors)
3751                 prev = test_c(&m, _("sectors"));
3752         if (!cylinders)
3753                 prev = test_c(&m, _("cylinders"));
3754         if (!m)
3755                 return 0;
3756
3757         fprintf(stderr, "%s%s.\n"
3758 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3759                         "You can do this from the extra functions menu.\n"
3760 #endif
3761                 , prev ? _(" and ") : " ", m);
3762
3763         return 1;
3764 }
3765
3766 static void update_units(void)
3767 {
3768         int cyl_units = heads * sectors;
3769
3770         if (display_in_cyl_units && cyl_units)
3771                 units_per_sector = cyl_units;
3772         else
3773                 units_per_sector = 1;   /* in sectors */
3774 }
3775
3776 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3777 static void
3778 warn_cylinders(void)
3779 {
3780         if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
3781                 fprintf(stderr, _("\n"
3782 "The number of cylinders for this disk is set to %d.\n"
3783 "There is nothing wrong with that, but this is larger than 1024,\n"
3784 "and could in certain setups cause problems with:\n"
3785 "1) software that runs at boot time (e.g., old versions of LILO)\n"
3786 "2) booting and partitioning software from other OSs\n"
3787 "   (e.g., DOS FDISK, OS/2 FDISK)\n"),
3788                         cylinders);
3789 }
3790 #endif
3791
3792 static void
3793 read_extended(int ext)
3794 {
3795         int i;
3796         struct pte *pex;
3797         struct partition *p, *q;
3798
3799         ext_index = ext;
3800         pex = &ptes[ext];
3801         pex->ext_pointer = pex->part_table;
3802
3803         p = pex->part_table;
3804         if (!get_start_sect(p)) {
3805                 fprintf(stderr,
3806                         _("Bad offset in primary extended partition\n"));
3807                 return;
3808         }
3809
3810         while (IS_EXTENDED(p->sys_ind)) {
3811                 struct pte *pe = &ptes[partitions];
3812
3813                 if (partitions >= MAXIMUM_PARTS) {
3814                         /* This is not a Linux restriction, but
3815                            this program uses arrays of size MAXIMUM_PARTS.
3816                            Do not try to `improve' this test. */
3817                         struct pte *pre = &ptes[partitions-1];
3818 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3819                         fprintf(stderr,
3820                                 _("Warning: deleting partitions after %d\n"),
3821                                 partitions);
3822                         pre->changed = 1;
3823 #endif
3824                         clear_partition(pre->ext_pointer);
3825                         return;
3826                 }
3827
3828                 read_pte(pe, extended_offset + get_start_sect(p));
3829
3830                 if (!extended_offset)
3831                         extended_offset = get_start_sect(p);
3832
3833                 q = p = pt_offset(pe->sectorbuffer, 0);
3834                 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3835                         if (IS_EXTENDED(p->sys_ind)) {
3836                                 if (pe->ext_pointer)
3837                                         fprintf(stderr,
3838                                                 _("Warning: extra link "
3839                                                   "pointer in partition table"
3840                                                   " %d\n"), partitions + 1);
3841                                 else
3842                                         pe->ext_pointer = p;
3843                         } else if (p->sys_ind) {
3844                                 if (pe->part_table)
3845                                         fprintf(stderr,
3846                                                 _("Warning: ignoring extra "
3847                                                   "data in partition table"
3848                                                   " %d\n"), partitions + 1);
3849                                 else
3850                                         pe->part_table = p;
3851                         }
3852                 }
3853
3854                 /* very strange code here... */
3855                 if (!pe->part_table) {
3856                         if (q != pe->ext_pointer)
3857                                 pe->part_table = q;
3858                         else
3859                                 pe->part_table = q + 1;
3860                 }
3861                 if (!pe->ext_pointer) {
3862                         if (q != pe->part_table)
3863                                 pe->ext_pointer = q;
3864                         else
3865                                 pe->ext_pointer = q + 1;
3866                 }
3867
3868                 p = pe->ext_pointer;
3869                 partitions++;
3870         }
3871
3872 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3873         /* remove empty links */
3874  remove:
3875         for (i = 4; i < partitions; i++) {
3876                 struct pte *pe = &ptes[i];
3877
3878                 if (!get_nr_sects(pe->part_table) &&
3879                         (partitions > 5 || ptes[4].part_table->sys_ind)) {
3880                         printf("omitting empty partition (%d)\n", i+1);
3881                         delete_partition(i);
3882                         goto remove;    /* numbering changed */
3883                 }
3884         }
3885 #endif
3886 }
3887
3888 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
3889 static void
3890 create_doslabel(void)
3891 {
3892         int i;
3893
3894         fprintf(stderr,
3895         _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3896           "until you decide to write them. After that, of course, the previous\n"
3897           "content won't be recoverable.\n\n"));
3898
3899         current_label_type = label_dos;
3900
3901 #ifdef CONFIG_FEATURE_OSF_LABEL
3902         possibly_osf_label = 0;
3903 #endif
3904         partitions = 4;
3905
3906         for (i = 510-64; i < 510; i++)
3907                 MBRbuffer[i] = 0;
3908         write_part_table_flag(MBRbuffer);
3909         extended_offset = 0;
3910         set_all_unchanged();
3911         set_changed(0);
3912         get_boot(create_empty_dos);
3913 }
3914 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3915
3916 static void
3917 get_sectorsize(void)
3918 {
3919         if (!user_set_sector_size) {
3920                 int arg;
3921                 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3922                         sector_size = arg;
3923                 if (sector_size != DEFAULT_SECTOR_SIZE)
3924                         printf(_("Note: sector size is %d (not %d)\n"),
3925                                    sector_size, DEFAULT_SECTOR_SIZE);
3926         }
3927 }
3928
3929 static inline void
3930 get_kernel_geometry(void)
3931 {
3932         struct hd_geometry geometry;
3933
3934         if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3935                 kern_heads = geometry.heads;
3936                 kern_sectors = geometry.sectors;
3937                 /* never use geometry.cylinders - it is truncated */
3938         }
3939 }
3940
3941 static void
3942 get_partition_table_geometry(void)
3943 {
3944         const unsigned char *bufp = (const unsigned char *)MBRbuffer;
3945         struct partition *p;
3946         int i, h, s, hh, ss;
3947         int first = 1;
3948         int bad = 0;
3949
3950         if (!(valid_part_table_flag((char*)bufp)))
3951                 return;
3952
3953         hh = ss = 0;
3954         for (i = 0; i < 4; i++) {
3955                 p = pt_offset(bufp, i);
3956                 if (p->sys_ind != 0) {
3957                         h = p->end_head + 1;
3958                         s = (p->end_sector & 077);
3959                         if (first) {
3960                                 hh = h;
3961                                 ss = s;
3962                                 first = 0;
3963                         } else if (hh != h || ss != s)
3964                                 bad = 1;
3965                 }
3966         }
3967
3968         if (!first && !bad) {
3969                 pt_heads = hh;
3970                 pt_sectors = ss;
3971         }
3972 }
3973
3974 static void
3975 get_geometry(void)
3976 {
3977         int sec_fac;
3978         unsigned long long bytes;       /* really u64 */
3979
3980         get_sectorsize();
3981         sec_fac = sector_size / 512;
3982 #ifdef CONFIG_FEATURE_SUN_LABEL
3983         guess_device_type();
3984 #endif
3985         heads = cylinders = sectors = 0;
3986         kern_heads = kern_sectors = 0;
3987         pt_heads = pt_sectors = 0;
3988
3989         get_kernel_geometry();
3990         get_partition_table_geometry();
3991
3992         heads = user_heads ? user_heads :
3993                 pt_heads ? pt_heads :
3994                 kern_heads ? kern_heads : 255;
3995         sectors = user_sectors ? user_sectors :
3996                 pt_sectors ? pt_sectors :
3997                 kern_sectors ? kern_sectors : 63;
3998         if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3999                 /* got bytes */
4000         } else {
4001                 unsigned long longsectors;
4002
4003         if (ioctl(fd, BLKGETSIZE, &longsectors))
4004                 longsectors = 0;
4005                         bytes = ((unsigned long long) longsectors) << 9;
4006         }
4007
4008         total_number_of_sectors = (bytes >> 9);
4009
4010         sector_offset = 1;
4011         if (dos_compatible_flag)
4012                 sector_offset = sectors;
4013
4014         cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
4015         if (!cylinders)
4016                 cylinders = user_cylinders;
4017 }
4018
4019 /*
4020  * Read MBR.  Returns:
4021  *   -1: no 0xaa55 flag present (possibly entire disk BSD)
4022  *    0: found or created label
4023  *    1: I/O error
4024  */
4025 static int
4026 get_boot(enum action what)
4027 {
4028         int i;
4029
4030         partitions = 4;
4031
4032         for (i = 0; i < 4; i++) {
4033                 struct pte *pe = &ptes[i];
4034
4035                 pe->part_table = pt_offset(MBRbuffer, i);
4036                 pe->ext_pointer = NULL;
4037                 pe->offset = 0;
4038                 pe->sectorbuffer = MBRbuffer;
4039 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4040                 pe->changed = (what == create_empty_dos);
4041 #endif
4042         }
4043
4044 #ifdef CONFIG_FEATURE_SUN_LABEL
4045         if (what == create_empty_sun && check_sun_label())
4046                 return 0;
4047 #endif
4048
4049         memset(MBRbuffer, 0, 512);
4050
4051 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4052         if (what == create_empty_dos)
4053                 goto got_dos_table;             /* skip reading disk */
4054
4055         if ((fd = open(disk_device, type_open)) < 0) {
4056                 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4057                         if (what == try_only)
4058                                 return 1;
4059                         fdisk_fatal(unable_to_open);
4060                 } else
4061                         printf(_("You will not be able to write "
4062                                 "the partition table.\n"));
4063         }
4064
4065         if (512 != read(fd, MBRbuffer, 512)) {
4066                 if (what == try_only)
4067                         return 1;
4068                 fdisk_fatal(unable_to_read);
4069         }
4070 #else
4071         if ((fd = open(disk_device, O_RDONLY)) < 0)
4072                 return 1;
4073         if (512 != read(fd, MBRbuffer, 512))
4074                 return 1;
4075 #endif
4076
4077         get_geometry();
4078
4079         update_units();
4080
4081 #ifdef CONFIG_FEATURE_SUN_LABEL
4082         if (check_sun_label())
4083                 return 0;
4084 #endif
4085
4086 #ifdef CONFIG_FEATURE_SGI_LABEL
4087         if (check_sgi_label())
4088                 return 0;
4089 #endif
4090
4091 #ifdef CONFIG_FEATURE_AIX_LABEL
4092         if (check_aix_label())
4093                 return 0;
4094 #endif
4095
4096 #ifdef CONFIG_FEATURE_OSF_LABEL
4097         if (check_osf_label()) {
4098                 possibly_osf_label = 1;
4099                 if (!valid_part_table_flag(MBRbuffer)) {
4100                         current_label_type = label_osf;
4101                         return 0;
4102                 }
4103                 printf(_("This disk has both DOS and BSD magic.\n"
4104                          "Give the 'b' command to go to BSD mode.\n"));
4105         }
4106 #endif
4107
4108 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4109  got_dos_table:
4110 #endif
4111
4112         if (!valid_part_table_flag(MBRbuffer)) {
4113 #ifndef CONFIG_FEATURE_FDISK_WRITABLE
4114                 return -1;
4115 #else
4116                 switch (what) {
4117                 case fdisk:
4118                         fprintf(stderr,
4119                                 _("Device contains neither a valid DOS "
4120                                   "partition table, nor Sun, SGI or OSF "
4121                                   "disklabel\n"));
4122 #ifdef __sparc__
4123 #ifdef CONFIG_FEATURE_SUN_LABEL
4124                         create_sunlabel();
4125 #endif
4126 #else
4127                         create_doslabel();
4128 #endif
4129                         return 0;
4130                 case try_only:
4131                         return -1;
4132                 case create_empty_dos:
4133 #ifdef CONFIG_FEATURE_SUN_LABEL
4134                 case create_empty_sun:
4135 #endif
4136                         break;
4137                 default:
4138                         fprintf(stderr, _("Internal error\n"));
4139                         exit(1);
4140                 }
4141 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4142         }
4143
4144 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4145         warn_cylinders();
4146 #endif
4147         warn_geometry();
4148
4149         for (i = 0; i < 4; i++) {
4150                 struct pte *pe = &ptes[i];
4151
4152                 if (IS_EXTENDED(pe->part_table->sys_ind)) {
4153                         if (partitions != 4)
4154                                 fprintf(stderr, _("Ignoring extra extended "
4155                                         "partition %d\n"), i + 1);
4156                         else
4157                                 read_extended(i);
4158                 }
4159         }
4160
4161         for (i = 3; i < partitions; i++) {
4162                 struct pte *pe = &ptes[i];
4163
4164                 if (!valid_part_table_flag(pe->sectorbuffer)) {
4165                         fprintf(stderr,
4166                                 _("Warning: invalid flag 0x%04x of partition "
4167                                 "table %d will be corrected by w(rite)\n"),
4168                                 part_table_flag(pe->sectorbuffer), i + 1);
4169 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4170                         pe->changed = 1;
4171 #endif
4172                 }
4173         }
4174
4175         return 0;
4176 }
4177
4178 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4179 /*
4180  * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4181  * If the user hits Enter, DFLT is returned.
4182  * Answers like +10 are interpreted as offsets from BASE.
4183  *
4184  * There is no default if DFLT is not between LOW and HIGH.
4185  */
4186 static uint
4187 read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4188 {
4189         uint i;
4190         int default_ok = 1;
4191         static char *ms = NULL;
4192         static int mslen = 0;
4193
4194         if (!ms || strlen(mesg)+100 > mslen) {
4195                 mslen = strlen(mesg)+200;
4196                 ms = xrealloc(ms,mslen);
4197         }
4198
4199         if (dflt < low || dflt > high)
4200                 default_ok = 0;
4201
4202         if (default_ok)
4203                 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
4204                          mesg, low, high, dflt);
4205         else
4206                 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
4207
4208         while (1) {
4209                 int use_default = default_ok;
4210
4211                 /* ask question and read answer */
4212                 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4213                  && *line_ptr != '-' && *line_ptr != '+')
4214                         continue;
4215
4216                 if (*line_ptr == '+' || *line_ptr == '-') {
4217                         int minus = (*line_ptr == '-');
4218                         int absolute = 0;
4219
4220                         i = atoi(line_ptr+1);
4221
4222                         while (isdigit(*++line_ptr))
4223                                 use_default = 0;
4224
4225                         switch (*line_ptr) {
4226                         case 'c':
4227                         case 'C':
4228                                 if (!display_in_cyl_units)
4229                                         i *= heads * sectors;
4230                                 break;
4231                         case 'K':
4232                                 absolute = 1024;
4233                                 break;
4234                         case 'k':
4235                                 absolute = 1000;
4236                                 break;
4237                         case 'm':
4238                         case 'M':
4239                                 absolute = 1000000;
4240                                 break;
4241                         case 'g':
4242                         case 'G':
4243                                 absolute = 1000000000;
4244                                 break;
4245                         default:
4246                                 break;
4247                         }
4248                         if (absolute) {
4249                                 unsigned long long bytes;
4250                                 unsigned long unit;
4251
4252                                 bytes = (unsigned long long) i * absolute;
4253                                 unit = sector_size * units_per_sector;
4254                                 bytes += unit/2; /* round */
4255                                 bytes /= unit;
4256                                 i = bytes;
4257                         }
4258                         if (minus)
4259                                 i = -i;
4260                         i += base;
4261                 } else {
4262                         i = atoi(line_ptr);
4263                         while (isdigit(*line_ptr)) {
4264                                 line_ptr++;
4265                                 use_default = 0;
4266                         }
4267                 }
4268                 if (use_default)
4269                         printf(_("Using default value %u\n"), i = dflt);
4270                 if (i >= low && i <= high)
4271                         break;
4272                 else
4273                         printf(_("Value out of range.\n"));
4274         }
4275         return i;
4276 }
4277
4278 static int
4279 get_partition(int warn, int max)
4280 {
4281         struct pte *pe;
4282         int i;
4283
4284         i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4285         pe = &ptes[i];
4286
4287         if (warn) {
4288                 if (
4289                         (
4290                                 label_sun != current_label_type && 
4291                                 label_sgi != current_label_type && 
4292                                 !pe->part_table->sys_ind
4293                         )
4294 #ifdef CONFIG_FEATURE_SUN_LABEL
4295                         || (
4296                                 label_sun == current_label_type &&
4297                                 (
4298                                         !sunlabel->partitions[i].num_sectors
4299                                         || !sunlabel->infos[i].id
4300                                 )
4301                         )
4302 #endif
4303 #ifdef CONFIG_FEATURE_SGI_LABEL
4304                         || (
4305                                 label_sgi == current_label_type &&
4306                                  !sgi_get_num_sectors(i)
4307                         )
4308 #endif
4309                 ){
4310                         fprintf(stderr,
4311                                 _("Warning: partition %d has empty type\n"),
4312                                 i+1
4313                         );
4314                 }
4315         }
4316         return i;
4317 }
4318
4319 static int
4320 get_existing_partition(int warn, int max)
4321 {
4322         int pno = -1;
4323         int i;
4324
4325         for (i = 0; i < max; i++) {
4326                 struct pte *pe = &ptes[i];
4327                 struct partition *p = pe->part_table;
4328
4329                 if (p && !is_cleared_partition(p)) {
4330                         if (pno >= 0)
4331                                 goto not_unique;
4332                         pno = i;
4333                 }
4334         }
4335         if (pno >= 0) {
4336                 printf(_("Selected partition %d\n"), pno+1);
4337                 return pno;
4338         }
4339         printf(_("No partition is defined yet!\n"));
4340         return -1;
4341
4342  not_unique:
4343         return get_partition(warn, max);
4344 }
4345
4346 static int
4347 get_nonexisting_partition(int warn, int max)
4348 {
4349         int pno = -1;
4350         int i;
4351
4352         for (i = 0; i < max; i++) {
4353                 struct pte *pe = &ptes[i];
4354                 struct partition *p = pe->part_table;
4355
4356                 if (p && is_cleared_partition(p)) {
4357                         if (pno >= 0)
4358                                 goto not_unique;
4359                         pno = i;
4360                 }
4361         }
4362         if (pno >= 0) {
4363                 printf(_("Selected partition %d\n"), pno+1);
4364                 return pno;
4365         }
4366         printf(_("All primary partitions have been defined already!\n"));
4367         return -1;
4368
4369  not_unique:
4370         return get_partition(warn, max);
4371 }
4372
4373
4374 void change_units(void)
4375 {
4376         display_in_cyl_units = !display_in_cyl_units;
4377         update_units();
4378         printf(_("Changing display/entry units to %s\n"),
4379                 str_units(PLURAL));
4380 }
4381
4382 static void
4383 toggle_active(int i)
4384 {
4385         struct pte *pe = &ptes[i];
4386         struct partition *p = pe->part_table;
4387
4388         if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
4389                 fprintf(stderr,
4390                         _("WARNING: Partition %d is an extended partition\n"),
4391                         i + 1);
4392         p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4393         pe->changed = 1;
4394 }
4395
4396 static void
4397 toggle_dos_compatibility_flag(void)
4398 {
4399         dos_compatible_flag = ~dos_compatible_flag;
4400         if (dos_compatible_flag) {
4401                 sector_offset = sectors;
4402                 printf(_("DOS Compatibility flag is set\n"));
4403         }
4404         else {
4405                 sector_offset = 1;
4406                 printf(_("DOS Compatibility flag is not set\n"));
4407         }
4408 }
4409
4410 static void
4411 delete_partition(int i)
4412 {
4413         struct pte *pe = &ptes[i];
4414         struct partition *p = pe->part_table;
4415         struct partition *q = pe->ext_pointer;
4416
4417 /* Note that for the fifth partition (i == 4) we don't actually
4418  * decrement partitions.
4419  */
4420
4421         if (warn_geometry())
4422                 return;         /* C/H/S not set */
4423         pe->changed = 1;
4424
4425 #ifdef CONFIG_FEATURE_SUN_LABEL
4426         if (label_sun == current_label_type) {
4427                 sun_delete_partition(i);
4428                 return;
4429         }
4430 #endif
4431 #ifdef CONFIG_FEATURE_SGI_LABEL
4432         if (label_sgi == current_label_type) {
4433                 sgi_delete_partition(i);
4434                 return;
4435         }
4436 #endif
4437
4438         if (i < 4) {
4439                 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
4440                         partitions = 4;
4441                         ptes[ext_index].ext_pointer = NULL;
4442                         extended_offset = 0;
4443                 }
4444                 clear_partition(p);
4445                 return;
4446         }
4447
4448         if (!q->sys_ind && i > 4) {
4449                 /* the last one in the chain - just delete */
4450                 --partitions;
4451                 --i;
4452                 clear_partition(ptes[i].ext_pointer);
4453                 ptes[i].changed = 1;
4454         } else {
4455                 /* not the last one - further ones will be moved down */
4456                 if (i > 4) {
4457                         /* delete this link in the chain */
4458                         p = ptes[i-1].ext_pointer;
4459                         *p = *q;
4460                         set_start_sect(p, get_start_sect(q));
4461                         set_nr_sects(p, get_nr_sects(q));
4462                         ptes[i-1].changed = 1;
4463                 } else if (partitions > 5) {    /* 5 will be moved to 4 */
4464                         /* the first logical in a longer chain */
4465                         pe = &ptes[5];
4466
4467                         if (pe->part_table) /* prevent SEGFAULT */
4468                                 set_start_sect(pe->part_table,
4469                                                    get_partition_start(pe) -
4470                                                    extended_offset);
4471                         pe->offset = extended_offset;
4472                         pe->changed = 1;
4473                 }
4474
4475                 if (partitions > 5) {
4476                         partitions--;
4477                         while (i < partitions) {
4478                                 ptes[i] = ptes[i+1];
4479                                 i++;
4480                         }
4481                 } else
4482                         /* the only logical: clear only */
4483                         clear_partition(ptes[i].part_table);
4484         }
4485 }
4486
4487 static void
4488 change_sysid(void)
4489 {
4490         int i, sys, origsys;
4491         struct partition *p;
4492
4493 #ifdef CONFIG_FEATURE_SGI_LABEL
4494         /* If sgi_label then don't use get_existing_partition,
4495            let the user select a partition, since get_existing_partition()
4496            only works for Linux like partition tables. */
4497         if (label_sgi != current_label_type) {
4498                 i = get_existing_partition(0, partitions);
4499         } else {
4500                 i = get_partition(0, partitions);
4501         }
4502 #else
4503         i = get_existing_partition(0, partitions);
4504 #endif
4505         if (i == -1)
4506                 return;
4507         p = ptes[i].part_table;
4508         origsys = sys = get_sysid(i);
4509
4510         /* if changing types T to 0 is allowed, then
4511            the reverse change must be allowed, too */
4512         if (!sys && label_sgi != current_label_type &&
4513                 label_sun != current_label_type && !get_nr_sects(p))
4514         {
4515                 printf(_("Partition %d does not exist yet!\n"), i + 1);
4516         }else{
4517             while (1) {
4518                 sys = read_hex (get_sys_types());
4519
4520                 if (!sys && label_sgi != current_label_type &&
4521                         label_sun != current_label_type)
4522                 {
4523                         printf(_("Type 0 means free space to many systems\n"
4524                                    "(but not to Linux). Having partitions of\n"
4525                                    "type 0 is probably unwise. You can delete\n"
4526                                    "a partition using the `d' command.\n"));
4527                         /* break; */
4528                 }
4529
4530                 if (label_sun != current_label_type && label_sgi != current_label_type) {
4531                         if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
4532                                 printf(_("You cannot change a partition into"
4533                                            " an extended one or vice versa\n"
4534                                            "Delete it first.\n"));
4535                                 break;
4536                         }
4537                 }
4538
4539                 if (sys < 256) {
4540 #ifdef CONFIG_FEATURE_SUN_LABEL
4541                         if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
4542                                 printf(_("Consider leaving partition 3 "
4543                                            "as Whole disk (5),\n"
4544                                            "as SunOS/Solaris expects it and "
4545                                            "even Linux likes it.\n\n"));
4546 #endif
4547 #ifdef CONFIG_FEATURE_SGI_LABEL
4548                         if (label_sgi == current_label_type &&
4549                                 (
4550                                         (i == 10 && sys != ENTIRE_DISK) ||
4551                                         (i == 8 && sys != 0)
4552                                 )
4553                         ){
4554                                 printf(_("Consider leaving partition 9 "
4555                                            "as volume header (0),\nand "
4556                                            "partition 11 as entire volume (6)"
4557                                            "as IRIX expects it.\n\n"));
4558                         }
4559 #endif
4560                         if (sys == origsys)
4561                                 break;
4562 #ifdef CONFIG_FEATURE_SUN_LABEL
4563                         if (label_sun == current_label_type) {
4564                                 sun_change_sysid(i, sys);
4565                         } else
4566 #endif
4567 #ifdef CONFIG_FEATURE_SGI_LABEL
4568                         if (label_sgi == current_label_type) {
4569                                 sgi_change_sysid(i, sys);
4570                         } else
4571 #endif
4572                                 p->sys_ind = sys;
4573
4574                         printf(_("Changed system type of partition %d "
4575                                 "to %x (%s)\n"), i + 1, sys,
4576                                 partition_type(sys));
4577                         ptes[i].changed = 1;
4578                         if (is_dos_partition(origsys) ||
4579                                 is_dos_partition(sys))
4580                                 dos_changed = 1;
4581                         break;
4582                 }
4583             }
4584         }
4585 }
4586 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4587
4588
4589 /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4590  * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4591  * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4592  * Lubkin Oct.  1991). */
4593
4594 static void
4595 long2chs(ulong ls, uint *c, uint *h, uint *s)
4596 {
4597         int spc = heads * sectors;
4598
4599         *c = ls / spc;
4600         ls = ls % spc;
4601         *h = ls / sectors;
4602         *s = ls % sectors + 1;  /* sectors count from 1 */
4603 }
4604
4605 static void
4606 check_consistency(const struct partition *p, int partition)
4607 {
4608         uint pbc, pbh, pbs;          /* physical beginning c, h, s */
4609         uint pec, peh, pes;          /* physical ending c, h, s */
4610         uint lbc, lbh, lbs;          /* logical beginning c, h, s */
4611         uint lec, leh, les;          /* logical ending c, h, s */
4612
4613         if (!heads || !sectors || (partition >= 4))
4614                 return;         /* do not check extended partitions */
4615
4616 /* physical beginning c, h, s */
4617         pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4618         pbh = p->head;
4619         pbs = p->sector & 0x3f;
4620
4621 /* physical ending c, h, s */
4622         pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4623         peh = p->end_head;
4624         pes = p->end_sector & 0x3f;
4625
4626 /* compute logical beginning (c, h, s) */
4627         long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4628
4629 /* compute logical ending (c, h, s) */
4630         long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4631
4632 /* Same physical / logical beginning? */
4633         if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4634                 printf(_("Partition %d has different physical/logical "
4635                         "beginnings (non-Linux?):\n"), partition + 1);
4636                 printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
4637                 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4638         }
4639
4640 /* Same physical / logical ending? */
4641         if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4642                 printf(_("Partition %d has different physical/logical "
4643                         "endings:\n"), partition + 1);
4644                 printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
4645                 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4646         }
4647
4648 #if 0
4649 /* Beginning on cylinder boundary? */
4650         if (pbh != !pbc || pbs != 1) {
4651                 printf(_("Partition %i does not start on cylinder "
4652                         "boundary:\n"), partition + 1);
4653                 printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
4654                 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4655         }
4656 #endif
4657
4658 /* Ending on cylinder boundary? */
4659         if (peh != (heads - 1) || pes != sectors) {
4660                 printf(_("Partition %i does not end on cylinder boundary.\n"),
4661                         partition + 1);
4662 #if 0
4663                 printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
4664                 printf(_("should be (%d, %d, %d)\n"),
4665                 pec, heads - 1, sectors);
4666 #endif
4667         }
4668 }
4669
4670 static void
4671 list_disk_geometry(void)
4672 {
4673         long long bytes = (total_number_of_sectors << 9);
4674         long megabytes = bytes/1000000;
4675
4676         if (megabytes < 10000)
4677                 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4678                            disk_device, megabytes, bytes);
4679         else
4680                 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4681                            disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4682         printf(_("%d heads, %d sectors/track, %d cylinders"),
4683                    heads, sectors, cylinders);
4684         if (units_per_sector == 1)
4685                 printf(_(", total %llu sectors"),
4686                            total_number_of_sectors / (sector_size/512));
4687         printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
4688                    str_units(PLURAL),
4689                    units_per_sector, sector_size, units_per_sector * sector_size);
4690 }
4691
4692 /*
4693  * Check whether partition entries are ordered by their starting positions.
4694  * Return 0 if OK. Return i if partition i should have been earlier.
4695  * Two separate checks: primary and logical partitions.
4696  */
4697 static int
4698 wrong_p_order(int *prev)
4699 {
4700         const struct pte *pe;
4701         const struct partition *p;
4702         off_t last_p_start_pos = 0, p_start_pos;
4703         int i, last_i = 0;
4704
4705         for (i = 0 ; i < partitions; i++) {
4706                 if (i == 4) {
4707                         last_i = 4;
4708                         last_p_start_pos = 0;
4709                 }
4710                 pe = &ptes[i];
4711                 if ((p = pe->part_table)->sys_ind) {
4712                         p_start_pos = get_partition_start(pe);
4713
4714                         if (last_p_start_pos > p_start_pos) {
4715                                 if (prev)
4716                                         *prev = last_i;
4717                                 return i;
4718                         }
4719
4720                         last_p_start_pos = p_start_pos;
4721                         last_i = i;
4722                 }
4723         }
4724         return 0;
4725 }
4726
4727 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
4728 /*
4729  * Fix the chain of logicals.
4730  * extended_offset is unchanged, the set of sectors used is unchanged
4731  * The chain is sorted so that sectors increase, and so that
4732  * starting sectors increase.
4733  *
4734  * After this it may still be that cfdisk doesnt like the table.
4735  * (This is because cfdisk considers expanded parts, from link to
4736  * end of partition, and these may still overlap.)
4737  * Now
4738  *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4739  * may help.
4740  */
4741 static void
4742 fix_chain_of_logicals(void)
4743 {
4744         int j, oj, ojj, sj, sjj;
4745         struct partition *pj,*pjj,tmp;
4746
4747         /* Stage 1: sort sectors but leave sector of part 4 */
4748         /* (Its sector is the global extended_offset.) */
4749  stage1:
4750         for (j = 5; j < partitions-1; j++) {
4751                 oj = ptes[j].offset;
4752                 ojj = ptes[j+1].offset;
4753                 if (oj > ojj) {
4754                         ptes[j].offset = ojj;
4755                         ptes[j+1].offset = oj;
4756                         pj = ptes[j].part_table;
4757                         set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4758                         pjj = ptes[j+1].part_table;
4759                         set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4760                         set_start_sect(ptes[j-1].ext_pointer,
4761                                            ojj-extended_offset);
4762                         set_start_sect(ptes[j].ext_pointer,
4763                                            oj-extended_offset);
4764                         goto stage1;
4765                 }
4766         }
4767
4768         /* Stage 2: sort starting sectors */
4769  stage2:
4770         for (j = 4; j < partitions-1; j++) {
4771                 pj = ptes[j].part_table;
4772                 pjj = ptes[j+1].part_table;
4773                 sj = get_start_sect(pj);
4774                 sjj = get_start_sect(pjj);
4775                 oj = ptes[j].offset;
4776                 ojj = ptes[j+1].offset;
4777                 if (oj+sj > ojj+sjj) {
4778                         tmp = *pj;
4779                         *pj = *pjj;
4780                         *pjj = tmp;
4781                         set_start_sect(pj, ojj+sjj-oj);
4782                         set_start_sect(pjj, oj+sj-ojj);
4783                         goto stage2;
4784                 }
4785         }
4786
4787         /* Probably something was changed */
4788         for (j = 4; j < partitions; j++)
4789                 ptes[j].changed = 1;
4790 }
4791
4792
4793 static void
4794 fix_partition_table_order(void)
4795 {
4796         struct pte *pei, *pek;
4797         int i,k;
4798
4799         if (!wrong_p_order(NULL)) {
4800                 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4801                 return;
4802         }
4803
4804         while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4805                 /* partition i should have come earlier, move it */
4806                 /* We have to move data in the MBR */
4807                 struct partition *pi, *pk, *pe, pbuf;
4808                 pei = &ptes[i];
4809                 pek = &ptes[k];
4810
4811                 pe = pei->ext_pointer;
4812                 pei->ext_pointer = pek->ext_pointer;
4813                 pek->ext_pointer = pe;
4814
4815                 pi = pei->part_table;
4816                 pk = pek->part_table;
4817
4818                 memmove(&pbuf, pi, sizeof(struct partition));
4819                 memmove(pi, pk, sizeof(struct partition));
4820                 memmove(pk, &pbuf, sizeof(struct partition));
4821
4822                 pei->changed = pek->changed = 1;
4823         }
4824
4825         if (i)
4826                 fix_chain_of_logicals();
4827
4828         printf("Done.\n");
4829
4830 }
4831 #endif
4832
4833 static void
4834 list_table(int xtra)
4835 {
4836         const struct partition *p;
4837         int i, w;
4838
4839 #ifdef CONFIG_FEATURE_SUN_LABEL
4840         if (label_sun == current_label_type) {
4841                 sun_list_table(xtra);
4842                 return;
4843         }
4844 #endif
4845
4846 #ifdef CONFIG_FEATURE_SGI_LABEL
4847         if (label_sgi == current_label_type) {
4848                 sgi_list_table(xtra);
4849                 return;
4850         }
4851 #endif
4852
4853         list_disk_geometry();
4854
4855 #ifdef CONFIG_FEATURE_OSF_LABEL
4856         if (label_osf == current_label_type) {
4857                 xbsd_print_disklabel(xtra);
4858                 return;
4859         }
4860 #endif
4861
4862         /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4863            but if the device name ends in a digit, say /dev/foo1,
4864            then the partition is called /dev/foo1p3. */
4865         w = strlen(disk_device);
4866         if (w && isdigit(disk_device[w-1]))
4867                 w++;
4868         if (w < 5)
4869                 w = 5;
4870
4871         printf(_("%*s Boot    Start       End    Blocks   Id  System\n"),
4872                    w+1, _("Device"));
4873
4874         for (i = 0; i < partitions; i++) {
4875                 const struct pte *pe = &ptes[i];
4876
4877                 p = pe->part_table;
4878                 if (p && !is_cleared_partition(p)) {
4879                         off_t psects = get_nr_sects(p);
4880                         off_t pblocks = psects;
4881                         unsigned int podd = 0;
4882
4883                         if (sector_size < 1024) {
4884                                 pblocks /= (1024 / sector_size);
4885                                 podd = psects % (1024 / sector_size);
4886                         }
4887                         if (sector_size > 1024)
4888                                 pblocks *= (sector_size / 1024);
4889                         printf(
4890                                 "%s  %c %11llu %11llu %11llu%c  %2x  %s\n",
4891                         partname(disk_device, i+1, w+2),
4892 /* boot flag */         !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4893                         ? '*' : '?',
4894 /* start */             (unsigned long long) cround(get_partition_start(pe)),
4895 /* end */               (unsigned long long) cround(get_partition_start(pe) + psects
4896                                 - (psects ? 1 : 0)),
4897 /* odd flag on end */   (unsigned long long) pblocks, podd ? '+' : ' ',
4898 /* type id */           p->sys_ind,
4899 /* type name */         partition_type(p->sys_ind));
4900                         check_consistency(p, i);
4901                 }
4902         }
4903
4904         /* Is partition table in disk order? It need not be, but... */
4905         /* partition table entries are not checked for correct order if this
4906            is a sgi, sun or aix labeled disk... */
4907         if (label_dos == current_label_type && wrong_p_order(NULL)) {
4908                 /* FIXME */
4909                 printf(_("\nPartition table entries are not in disk order\n"));
4910         }
4911 }
4912
4913 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
4914 static void
4915 x_list_table(int extend)
4916 {
4917         const struct pte *pe;
4918         const struct partition *p;
4919         int i;
4920
4921         printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4922                 disk_device, heads, sectors, cylinders);
4923         printf(_("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl    Start     Size ID\n"));
4924         for (i = 0 ; i < partitions; i++) {
4925                 pe = &ptes[i];
4926                 p = (extend ? pe->ext_pointer : pe->part_table);
4927                 if (p != NULL) {
4928                         printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
4929                                 i + 1, p->boot_ind, p->head,
4930                                 sector(p->sector),
4931                                 cylinder(p->sector, p->cyl), p->end_head,
4932                                 sector(p->end_sector),
4933                                 cylinder(p->end_sector, p->end_cyl),
4934                                 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4935                         if (p->sys_ind)
4936                                 check_consistency(p, i);
4937                 }
4938         }
4939 }
4940 #endif
4941
4942 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
4943 static void
4944 fill_bounds(off_t *first, off_t *last)
4945 {
4946         int i;
4947         const struct pte *pe = &ptes[0];
4948         const struct partition *p;
4949
4950         for (i = 0; i < partitions; pe++,i++) {
4951                 p = pe->part_table;
4952                 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
4953                         first[i] = 0xffffffff;
4954                         last[i] = 0;
4955                 } else {
4956                         first[i] = get_partition_start(pe);
4957                         last[i] = first[i] + get_nr_sects(p) - 1;
4958                 }
4959         }
4960 }
4961
4962 static void
4963 check(int n, uint h, uint s, uint c, off_t start)
4964 {
4965         off_t total, real_s, real_c;
4966
4967         real_s = sector(s) - 1;
4968         real_c = cylinder(s, c);
4969         total = (real_c * sectors + real_s) * heads + h;
4970         if (!total)
4971                 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4972         if (h >= heads)
4973                 fprintf(stderr,
4974                         _("Partition %d: head %d greater than maximum %d\n"),
4975                         n, h + 1, heads);
4976         if (real_s >= sectors)
4977                 fprintf(stderr, _("Partition %d: sector %d greater than "
4978                         "maximum %d\n"), n, s, sectors);
4979         if (real_c >= cylinders)
4980                 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4981                         "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
4982         if (cylinders <= 1024 && start != total)
4983                 fprintf(stderr,
4984                         _("Partition %d: previous sectors %llu disagrees with "
4985                         "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
4986 }
4987
4988 static void
4989 verify(void)
4990 {
4991         int i, j;
4992         uint total = 1;
4993         off_t first[partitions], last[partitions];
4994         struct partition *p;
4995
4996         if (warn_geometry())
4997                 return;
4998
4999 #ifdef CONFIG_FEATURE_SUN_LABEL
5000         if (label_sun == current_label_type) {
5001                 verify_sun();
5002                 return;
5003         }
5004 #endif
5005 #ifdef CONFIG_FEATURE_SGI_LABEL
5006         if (label_sgi == current_label_type) {
5007                 verify_sgi(1);
5008                 return;
5009         }
5010 #endif
5011
5012         fill_bounds(first, last);
5013         for (i = 0; i < partitions; i++) {
5014                 struct pte *pe = &ptes[i];
5015
5016                 p = pe->part_table;
5017                 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
5018                         check_consistency(p, i);
5019                         if (get_partition_start(pe) < first[i])
5020                                 printf(_("Warning: bad start-of-data in "
5021                                         "partition %d\n"), i + 1);
5022                         check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5023                                 last[i]);
5024                         total += last[i] + 1 - first[i];
5025                         for (j = 0; j < i; j++)
5026                         if ((first[i] >= first[j] && first[i] <= last[j])
5027                          || ((last[i] <= last[j] && last[i] >= first[j]))) {
5028                                 printf(_("Warning: partition %d overlaps "
5029                                         "partition %d.\n"), j + 1, i + 1);
5030                                 total += first[i] >= first[j] ?
5031                                         first[i] : first[j];
5032                                 total -= last[i] <= last[j] ?
5033                                         last[i] : last[j];
5034                         }
5035                 }
5036         }
5037
5038         if (extended_offset) {
5039                 struct pte *pex = &ptes[ext_index];
5040                 off_t e_last = get_start_sect(pex->part_table) +
5041                         get_nr_sects(pex->part_table) - 1;
5042
5043                 for (i = 4; i < partitions; i++) {
5044                         total++;
5045                         p = ptes[i].part_table;
5046                         if (!p->sys_ind) {
5047                                 if (i != 4 || i + 1 < partitions)
5048                                         printf(_("Warning: partition %d "
5049                                                 "is empty\n"), i + 1);
5050                         }
5051                         else if (first[i] < extended_offset ||
5052                                         last[i] > e_last)
5053                                 printf(_("Logical partition %d not entirely in "
5054                                         "partition %d\n"), i + 1, ext_index + 1);
5055                 }
5056         }
5057
5058         if (total > heads * sectors * cylinders)
5059                 printf(_("Total allocated sectors %d greater than the maximum "
5060                         "%d\n"), total, heads * sectors * cylinders);
5061         else if ((total = heads * sectors * cylinders - total) != 0)
5062                 printf(_("%d unallocated sectors\n"), total);
5063 }
5064
5065 static void
5066 add_partition(int n, int sys)
5067 {
5068         char mesg[256];         /* 48 does not suffice in Japanese */
5069         int i, num_read = 0;
5070         struct partition *p = ptes[n].part_table;
5071         struct partition *q = ptes[ext_index].part_table;
5072         long long llimit;
5073         off_t start, stop = 0, limit, temp,
5074                 first[partitions], last[partitions];
5075
5076         if (p && p->sys_ind) {
5077                 printf(_("Partition %d is already defined.  Delete "
5078                          "it before re-adding it.\n"), n + 1);
5079                 return;
5080         }
5081         fill_bounds(first, last);
5082         if (n < 4) {
5083                 start = sector_offset;
5084                 if (display_in_cyl_units || !total_number_of_sectors)
5085                         llimit = heads * sectors * cylinders - 1;
5086                 else
5087                         llimit = total_number_of_sectors - 1;
5088                 limit = llimit;
5089                 if (limit != llimit)
5090                         limit = 0x7fffffff;
5091                 if (extended_offset) {
5092                         first[ext_index] = extended_offset;
5093                         last[ext_index] = get_start_sect(q) +
5094                                 get_nr_sects(q) - 1;
5095                 }
5096         } else {
5097                 start = extended_offset + sector_offset;
5098                 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5099         }
5100         if (display_in_cyl_units)
5101                 for (i = 0; i < partitions; i++)
5102                         first[i] = (cround(first[i]) - 1) * units_per_sector;
5103
5104         snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5105         do {
5106                 temp = start;
5107                 for (i = 0; i < partitions; i++) {
5108                         int lastplusoff;
5109
5110                         if (start == ptes[i].offset)
5111                                 start += sector_offset;
5112                         lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
5113                         if (start >= first[i] && start <= lastplusoff)
5114                                 start = lastplusoff + 1;
5115                 }
5116                 if (start > limit)
5117                         break;
5118                 if (start >= temp+units_per_sector && num_read) {
5119                         printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
5120                         temp = start;
5121                         num_read = 0;
5122                 }
5123                 if (!num_read && start == temp) {
5124                         off_t saved_start;
5125
5126                         saved_start = start;
5127                         start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5128                                          0, mesg);
5129                         if (display_in_cyl_units) {
5130                                 start = (start - 1) * units_per_sector;
5131                                 if (start < saved_start) start = saved_start;
5132                         }
5133                         num_read = 1;
5134                 }
5135         } while (start != temp || !num_read);
5136         if (n > 4) {                    /* NOT for fifth partition */
5137                 struct pte *pe = &ptes[n];
5138
5139                 pe->offset = start - sector_offset;
5140                 if (pe->offset == extended_offset) { /* must be corrected */
5141                         pe->offset++;
5142                         if (sector_offset == 1)
5143                                 start++;
5144                 }
5145         }
5146
5147         for (i = 0; i < partitions; i++) {
5148                 struct pte *pe = &ptes[i];
5149
5150                 if (start < pe->offset && limit >= pe->offset)
5151                         limit = pe->offset - 1;
5152                 if (start < first[i] && limit >= first[i])
5153                         limit = first[i] - 1;
5154         }
5155         if (start > limit) {
5156                 printf(_("No free sectors available\n"));
5157                 if (n > 4)
5158                         partitions--;
5159                 return;
5160         }
5161         if (cround(start) == cround(limit)) {
5162                 stop = limit;
5163         } else {
5164                 snprintf(mesg, sizeof(mesg),
5165                          _("Last %s or +size or +sizeM or +sizeK"),
5166                          str_units(SINGULAR));
5167                 stop = read_int(cround(start), cround(limit), cround(limit),
5168                                 cround(start), mesg);
5169                 if (display_in_cyl_units) {
5170                         stop = stop * units_per_sector - 1;
5171                         if (stop >limit)
5172                                 stop = limit;
5173                 }
5174         }
5175
5176         set_partition(n, 0, start, stop, sys);
5177         if (n > 4)
5178                 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5179
5180         if (IS_EXTENDED(sys)) {
5181                 struct pte *pe4 = &ptes[4];
5182                 struct pte *pen = &ptes[n];
5183
5184                 ext_index = n;
5185                 pen->ext_pointer = p;
5186                 pe4->offset = extended_offset = start;
5187                 pe4->sectorbuffer = xcalloc(1, sector_size);
5188                 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5189                 pe4->ext_pointer = pe4->part_table + 1;
5190                 pe4->changed = 1;
5191                 partitions = 5;
5192         }
5193 }
5194
5195 static void
5196 add_logical(void)
5197 {
5198         if (partitions > 5 || ptes[4].part_table->sys_ind) {
5199                 struct pte *pe = &ptes[partitions];
5200
5201                 pe->sectorbuffer = xcalloc(1, sector_size);
5202                 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5203                 pe->ext_pointer = pe->part_table + 1;
5204                 pe->offset = 0;
5205                 pe->changed = 1;
5206                 partitions++;
5207         }
5208         add_partition(partitions - 1, LINUX_NATIVE);
5209 }
5210
5211 static void
5212 new_partition(void)
5213 {
5214         int i, free_primary = 0;
5215
5216         if (warn_geometry())
5217                 return;
5218
5219 #ifdef CONFIG_FEATURE_SUN_LABEL
5220         if (label_sun == current_label_type) {
5221                 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5222                 return;
5223         }
5224 #endif
5225 #ifdef CONFIG_FEATURE_SGI_LABEL
5226         if (label_sgi == current_label_type) {
5227                 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5228                 return;
5229         }
5230 #endif
5231 #ifdef CONFIG_FEATURE_AIX_LABEL
5232         if (label_aix == current_label_type) {
5233                 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5234                          "\n\tIf you want to add DOS-type partitions, create"
5235                          "\n\ta new empty DOS partition table first. (Use o.)"
5236                          "\n\tWARNING: "
5237                          "This will destroy the present disk contents.\n"));
5238                 return;
5239         }
5240 #endif
5241
5242         for (i = 0; i < 4; i++)
5243                 free_primary += !ptes[i].part_table->sys_ind;
5244
5245         if (!free_primary && partitions >= MAXIMUM_PARTS) {
5246                 printf(_("The maximum number of partitions has been created\n"));
5247                 return;
5248         }
5249
5250         if (!free_primary) {
5251                 if (extended_offset)
5252                         add_logical();
5253                 else
5254                         printf(_("You must delete some partition and add "
5255                                  "an extended partition first\n"));
5256         } else {
5257                 char c, line[LINE_LENGTH];
5258                 snprintf(line, sizeof(line), "%s\n   %s\n   p   primary "
5259                                                 "partition (1-4)\n",
5260                          "Command action", (extended_offset ?
5261                          "l   logical (5 or over)" : "e   extended"));
5262                 while (1) {
5263                         if ((c = read_char(line)) == 'p' || c == 'P') {
5264                                 i = get_nonexisting_partition(0, 4);
5265                                 if (i >= 0)
5266                                         add_partition(i, LINUX_NATIVE);
5267                                 return;
5268                         }
5269                         else if (c == 'l' && extended_offset) {
5270                                 add_logical();
5271                                 return;
5272                         }
5273                         else if (c == 'e' && !extended_offset) {
5274                                 i = get_nonexisting_partition(0, 4);
5275                                 if (i >= 0)
5276                                         add_partition(i, EXTENDED);
5277                                 return;
5278                         }
5279                         else
5280                                 printf(_("Invalid partition number "
5281                                          "for type `%c'\n"), c);
5282                 }
5283         }
5284 }
5285
5286 static void
5287 write_table(void)
5288 {
5289         int i;
5290
5291         if (label_dos == current_label_type) {
5292                 for (i = 0; i < 3; i++)
5293                         if (ptes[i].changed)
5294                                 ptes[3].changed = 1;
5295                 for (i = 3; i < partitions; i++) {
5296                         struct pte *pe = &ptes[i];
5297
5298                         if (pe->changed) {
5299                                 write_part_table_flag(pe->sectorbuffer);
5300                                 write_sector(pe->offset, pe->sectorbuffer);
5301                         }
5302                 }
5303         }
5304 #ifdef CONFIG_FEATURE_SGI_LABEL
5305         else if (label_sgi == current_label_type) {
5306                 /* no test on change? the printf below might be mistaken */
5307                 sgi_write_table();
5308         }
5309 #endif
5310 #ifdef CONFIG_FEATURE_SUN_LABEL
5311         else if (label_sun == current_label_type) {
5312                 int needw = 0;
5313
5314                 for (i = 0; i < 8; i++)
5315                         if (ptes[i].changed)
5316                                 needw = 1;
5317                 if (needw)
5318                         sun_write_table();
5319         }
5320 #endif
5321
5322         printf(_("The partition table has been altered!\n\n"));
5323         reread_partition_table(1);
5324 }
5325
5326 static void
5327 reread_partition_table(int leave)
5328 {
5329         int error = 0;
5330         int i;
5331
5332         printf(_("Calling ioctl() to re-read partition table.\n"));
5333         sync();
5334         sleep(2);
5335         if ((i = ioctl(fd, BLKRRPART)) != 0) {
5336                 error = errno;
5337         } else {
5338                 /* some kernel versions (1.2.x) seem to have trouble
5339                    rereading the partition table, but if asked to do it
5340                    twice, the second time works. - biro@yggdrasil.com */
5341                 sync();
5342                 sleep(2);
5343                 if ((i = ioctl(fd, BLKRRPART)) != 0)
5344                         error = errno;
5345         }
5346
5347         if (i) {
5348                 printf(_("\nWARNING: Re-reading the partition table "
5349                          "failed with error %d: %s.\n"
5350                          "The kernel still uses the old table.\n"
5351                          "The new table will be used "
5352                          "at the next reboot.\n"),
5353                         error, strerror(error));
5354         }
5355
5356         if (dos_changed)
5357                 printf(
5358                 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5359                 "partitions, please see the fdisk manual page for additional\n"
5360                 "information.\n"));
5361
5362         if (leave) {
5363                 close(fd);
5364
5365                 printf(_("Syncing disks.\n"));
5366                 sync();
5367                 sleep(4);               /* for sync() */
5368                 exit(!!i);
5369         }
5370 }
5371 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
5372
5373 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
5374 #define MAX_PER_LINE    16
5375 static void
5376 print_buffer(char *pbuffer)
5377 {
5378         int i,l;
5379
5380         for (i = 0, l = 0; i < sector_size; i++, l++) {
5381                 if (l == 0)
5382                         printf("0x%03X:", i);
5383                 printf(" %02X", (unsigned char) pbuffer[i]);
5384                 if (l == MAX_PER_LINE - 1) {
5385                         printf("\n");
5386                         l = -1;
5387                 }
5388         }
5389         if (l > 0)
5390                 printf("\n");
5391         printf("\n");
5392 }
5393
5394
5395 static void
5396 print_raw(void)
5397 {
5398         int i;
5399
5400         printf(_("Device: %s\n"), disk_device);
5401 #if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5402         if (label_sun == current_label_type || label_sgi == current_label_type)
5403                 print_buffer(MBRbuffer);
5404         else
5405 #endif
5406                 for (i = 3; i < partitions; i++)
5407                         print_buffer(ptes[i].sectorbuffer);
5408 }
5409
5410 static void
5411 move_begin(int i)
5412 {
5413         struct pte *pe = &ptes[i];
5414         struct partition *p = pe->part_table;
5415         off_t new, first;
5416
5417         if (warn_geometry())
5418                 return;
5419         if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
5420                 printf(_("Partition %d has no data area\n"), i + 1);
5421                 return;
5422         }
5423         first = get_partition_start(pe);
5424         new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5425                            _("New beginning of data")) - pe->offset;
5426
5427         if (new != get_nr_sects(p)) {
5428                 first = get_nr_sects(p) + get_start_sect(p) - new;
5429                 set_nr_sects(p, first);
5430                 set_start_sect(p, new);
5431                 pe->changed = 1;
5432         }
5433 }
5434
5435 static void
5436 xselect(void)
5437 {
5438         char c;
5439
5440         while (1) {
5441                 putchar('\n');
5442                 c = tolower(read_char(_("Expert command (m for help): ")));
5443                 switch (c) {
5444                 case 'a':
5445 #ifdef CONFIG_FEATURE_SUN_LABEL
5446                         if (label_sun == current_label_type)
5447                                 sun_set_alt_cyl();
5448 #endif
5449                         break;
5450                 case 'b':
5451                         if (label_dos == current_label_type)
5452                                 move_begin(get_partition(0, partitions));
5453                         break;
5454                 case 'c':
5455                         user_cylinders = cylinders =
5456                                 read_int(1, cylinders, 1048576, 0,
5457                                         _("Number of cylinders"));
5458 #ifdef CONFIG_FEATURE_SUN_LABEL
5459                         if (label_sun == current_label_type)
5460                                 sun_set_ncyl(cylinders);
5461 #endif
5462                         if (label_dos == current_label_type)
5463                                 warn_cylinders();
5464                         break;
5465                 case 'd':
5466                         print_raw();
5467                         break;
5468                 case 'e':
5469 #ifdef CONFIG_FEATURE_SGI_LABEL
5470                         if (label_sgi == current_label_type)
5471                                 sgi_set_xcyl();
5472                         else
5473 #endif
5474 #ifdef CONFIG_FEATURE_SUN_LABEL
5475                          if (label_sun == current_label_type)
5476                                 sun_set_xcyl();
5477                          else
5478 #endif
5479                         if (label_dos == current_label_type)
5480                                 x_list_table(1);
5481                         break;
5482                 case 'f':
5483                         if (label_dos == current_label_type)
5484                                 fix_partition_table_order();
5485                         break;
5486                 case 'g':
5487 #ifdef CONFIG_FEATURE_SGI_LABEL
5488                         create_sgilabel();
5489 #endif
5490                         break;
5491                 case 'h':
5492                         user_heads = heads = read_int(1, heads, 256, 0,
5493                                         _("Number of heads"));
5494                         update_units();
5495                         break;
5496                 case 'i':
5497 #ifdef CONFIG_FEATURE_SUN_LABEL
5498                         if (label_sun == current_label_type)
5499                                 sun_set_ilfact();
5500 #endif
5501                         break;
5502                 case 'o':
5503 #ifdef CONFIG_FEATURE_SUN_LABEL
5504                         if (label_sun == current_label_type)
5505                                 sun_set_rspeed();
5506 #endif
5507                         break;
5508                 case 'p':
5509 #ifdef CONFIG_FEATURE_SUN_LABEL
5510                         if (label_sun == current_label_type)
5511                                 list_table(1);
5512                         else
5513 #endif
5514                                 x_list_table(0);
5515                         break;
5516                 case 'q':
5517                         close(fd);
5518                         printf("\n");
5519                         exit(0);
5520                 case 'r':
5521                         return;
5522                 case 's':
5523                         user_sectors = sectors = read_int(1, sectors, 63, 0,
5524                                            _("Number of sectors"));
5525                         if (dos_compatible_flag) {
5526                                 sector_offset = sectors;
5527                                 fprintf(stderr, _("Warning: setting "
5528                                         "sector offset for DOS "
5529                                         "compatiblity\n"));
5530                         }
5531                         update_units();
5532                         break;
5533                 case 'v':
5534                         verify();
5535                         break;
5536                 case 'w':
5537                         write_table();  /* does not return */
5538                         break;
5539                 case 'y':
5540 #ifdef CONFIG_FEATURE_SUN_LABEL
5541                         if (label_sun == current_label_type)
5542                                 sun_set_pcylcount();
5543 #endif
5544                         break;
5545                 default:
5546                         xmenu();
5547                 }
5548         }
5549 }
5550 #endif /* ADVANCED mode */
5551
5552 static int
5553 is_ide_cdrom_or_tape(const char *device)
5554 {
5555         FILE *procf;
5556         char buf[100];
5557         struct stat statbuf;
5558         int is_ide = 0;
5559
5560         /* No device was given explicitly, and we are trying some
5561            likely things.  But opening /dev/hdc may produce errors like
5562            "hdc: tray open or drive not ready"
5563            if it happens to be a CD-ROM drive. It even happens that
5564            the process hangs on the attempt to read a music CD.
5565            So try to be careful. This only works since 2.1.73. */
5566
5567         if (strncmp("/dev/hd", device, 7))
5568                 return 0;
5569
5570         snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5571         procf = fopen(buf, "r");
5572         if (procf != NULL && fgets(buf, sizeof(buf), procf))
5573                 is_ide = (!strncmp(buf, "cdrom", 5) ||
5574                           !strncmp(buf, "tape", 4));
5575         else
5576                 /* Now when this proc file does not exist, skip the
5577                    device when it is read-only. */
5578                 if (stat(device, &statbuf) == 0)
5579                         is_ide = ((statbuf.st_mode & 0222) == 0);
5580
5581         if (procf)
5582                 fclose(procf);
5583         return is_ide;
5584 }
5585
5586
5587 static void
5588 try(const char *device, int user_specified)
5589 {
5590         int gb;
5591
5592         disk_device = device;
5593         if (setjmp(listingbuf))
5594                 return;
5595         if (!user_specified)
5596                 if (is_ide_cdrom_or_tape(device))
5597                         return;
5598         if ((fd = open(disk_device, type_open)) >= 0) {
5599                 gb = get_boot(try_only);
5600                 if (gb > 0) {   /* I/O error */
5601                         close(fd);
5602                 } else if (gb < 0) { /* no DOS signature */
5603                         list_disk_geometry();
5604                         if (label_aix == current_label_type){
5605                                 return;
5606                         }
5607 #ifdef CONFIG_FEATURE_OSF_LABEL
5608                         if (btrydev(device) < 0)
5609 #endif
5610                                 fprintf(stderr,
5611                                         _("Disk %s doesn't contain a valid "
5612                                         "partition table\n"), device);
5613                         close(fd);
5614                 } else {
5615                         close(fd);
5616                         list_table(0);
5617 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5618                         if (label_sun != current_label_type && partitions > 4){
5619                                 delete_partition(ext_index);
5620                         }
5621 #endif
5622                 }
5623         } else {
5624                 /* Ignore other errors, since we try IDE
5625                    and SCSI hard disks which may not be
5626                    installed on the system. */
5627                 if (errno == EACCES) {
5628                         fprintf(stderr, _("Cannot open %s\n"), device);
5629                         return;
5630                 }
5631         }
5632 }
5633
5634 /* for fdisk -l: try all things in /proc/partitions
5635    that look like a partition name (do not end in a digit) */
5636 static void
5637 tryprocpt(void)
5638 {
5639         FILE *procpt;
5640         char line[100], ptname[100], devname[120], *s;
5641         int ma, mi, sz;
5642
5643         procpt = bb_wfopen(PROC_PARTITIONS, "r");
5644
5645         while (fgets(line, sizeof(line), procpt)) {
5646                 if (sscanf(line, " %d %d %d %[^\n ]",
5647                                 &ma, &mi, &sz, ptname) != 4)
5648                         continue;
5649                 for (s = ptname; *s; s++);
5650                 if (isdigit(s[-1]))
5651                         continue;
5652                 sprintf(devname, "/dev/%s", ptname);
5653                 try(devname, 0);
5654         }
5655 #ifdef CONFIG_FEATURE_CLEAN_UP
5656         fclose(procpt);
5657 #endif
5658 }
5659
5660 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5661 static void
5662 unknown_command(int c)
5663 {
5664         printf(_("%c: unknown command\n"), c);
5665 }
5666 #endif
5667
5668 int fdisk_main(int argc, char **argv)
5669 {
5670         int c;
5671 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5672         int optl = 0;
5673 #endif
5674 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5675         int opts = 0;
5676 #endif
5677         /*
5678          * Calls:
5679          *  fdisk -v
5680          *  fdisk -l [-b sectorsize] [-u] device ...
5681          *  fdisk -s [partition] ...
5682          *  fdisk [-b sectorsize] [-u] device
5683          *
5684          * Options -C, -H, -S set the geometry.
5685          *
5686          */
5687         while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5688 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5689                                         "s"
5690 #endif
5691                                                 )) != -1) {
5692                 switch (c) {
5693                 case 'b':
5694                         /* Ugly: this sector size is really per device,
5695                            so cannot be combined with multiple disks,
5696                            and te same goes for the C/H/S options.
5697                         */
5698                         sector_size = atoi(optarg);
5699                         if (sector_size != 512 && sector_size != 1024 &&
5700                                 sector_size != 2048)
5701                                 bb_show_usage();
5702                         sector_offset = 2;
5703                         user_set_sector_size = 1;
5704                         break;
5705                 case 'C':
5706                         user_cylinders = atoi(optarg);
5707                         break;
5708                 case 'H':
5709                         user_heads = atoi(optarg);
5710                         if (user_heads <= 0 || user_heads >= 256)
5711                                 user_heads = 0;
5712                         break;
5713                 case 'S':
5714                         user_sectors = atoi(optarg);
5715                         if (user_sectors <= 0 || user_sectors >= 64)
5716                                 user_sectors = 0;
5717                         break;
5718                 case 'l':
5719 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5720                         optl = 1;
5721 #endif
5722                         break;
5723 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5724                 case 's':
5725                         opts = 1;
5726                         break;
5727 #endif
5728                 case 'u':
5729                         display_in_cyl_units = 0;
5730                         break;
5731                 case 'V':
5732                 case 'v':
5733                         printf("fdisk v" UTIL_LINUX_VERSION "\n");
5734                         return 0;
5735                 default:
5736                         bb_show_usage();
5737                 }
5738         }
5739
5740 #if 0
5741         printf(_("This kernel finds the sector size itself - "
5742                  "-b option ignored\n"));
5743 #else
5744         if (user_set_sector_size && argc-optind != 1)
5745                 printf(_("Warning: the -b (set sector size) option should"
5746                          " be used with one specified device\n"));
5747 #endif
5748
5749 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5750         if (optl) {
5751                 nowarn = 1;
5752 #endif
5753                 type_open = O_RDONLY;
5754                 if (argc > optind) {
5755                         int k;
5756 #if __GNUC__
5757                         /* avoid gcc warning:
5758                            variable `k' might be clobbered by `longjmp' */
5759                         (void)&k;
5760 #endif
5761                         listing = 1;
5762                         for (k = optind; k < argc; k++)
5763                                 try(argv[k], 1);
5764                 } else {
5765                         /* we no longer have default device names */
5766                         /* but, we can use /proc/partitions instead */
5767                         tryprocpt();
5768                 }
5769                 return 0;
5770 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5771         }
5772 #endif
5773
5774 #ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5775         if (opts) {
5776                 long size;
5777                 int j;
5778
5779                 nowarn = 1;
5780                 type_open = O_RDONLY;
5781
5782                 opts = argc - optind;
5783                 if (opts <= 0)
5784                         bb_show_usage();
5785
5786                 for (j = optind; j < argc; j++) {
5787                         disk_device = argv[j];
5788                         if ((fd = open(disk_device, type_open)) < 0)
5789                                 fdisk_fatal(unable_to_open);
5790                         if (ioctl(fd, BLKGETSIZE, &size))
5791                                 fdisk_fatal(ioctl_error);
5792                         close(fd);
5793                         if (opts == 1)
5794                                 printf("%ld\n", size/2);
5795                         else
5796                                 printf("%s: %ld\n", argv[j], size/2);
5797                 }
5798                 return 0;
5799         }
5800 #endif
5801
5802 #ifdef CONFIG_FEATURE_FDISK_WRITABLE
5803         if (argc-optind == 1)
5804                 disk_device = argv[optind];
5805         else
5806                 bb_show_usage();
5807
5808         get_boot(fdisk);
5809
5810 #ifdef CONFIG_FEATURE_OSF_LABEL
5811         if (label_osf == current_label_type) {
5812                 /* OSF label, and no DOS label */
5813                 printf(_("Detected an OSF/1 disklabel on %s, entering "
5814                          "disklabel mode.\n"),
5815                            disk_device);
5816                 bselect();
5817                 /*Why do we do this?  It seems to be counter-intuitive*/
5818                 current_label_type = label_dos;
5819                 /* If we return we may want to make an empty DOS label? */
5820         }
5821 #endif
5822
5823         while (1) {
5824                 putchar('\n');
5825                 c = tolower(read_char(_("Command (m for help): ")));
5826                 switch (c) {
5827                 case 'a':
5828                         if (label_dos == current_label_type)
5829                                 toggle_active(get_partition(1, partitions));
5830 #ifdef CONFIG_FEATURE_SUN_LABEL
5831                         else if (label_sun == current_label_type)
5832                                 toggle_sunflags(get_partition(1, partitions),
5833                                                 0x01);
5834 #endif
5835 #ifdef CONFIG_FEATURE_SGI_LABEL
5836                         else if (label_sgi == current_label_type)
5837                                 sgi_set_bootpartition(
5838                                         get_partition(1, partitions));
5839 #endif
5840                         else
5841                                 unknown_command(c);
5842                         break;
5843                 case 'b':
5844 #ifdef CONFIG_FEATURE_SGI_LABEL
5845                         if (label_sgi == current_label_type) {
5846                                 printf(_("\nThe current boot file is: %s\n"),
5847                                         sgi_get_bootfile());
5848                                 if (read_chars(_("Please enter the name of the "
5849                                                    "new boot file: ")) == '\n')
5850                                         printf(_("Boot file unchanged\n"));
5851                                 else
5852                                         sgi_set_bootfile(line_ptr);
5853                         } else
5854 #endif
5855 #ifdef CONFIG_FEATURE_OSF_LABEL
5856                                 bselect();
5857 #endif
5858                         break;
5859                 case 'c':
5860                         if (label_dos == current_label_type)
5861                                 toggle_dos_compatibility_flag();
5862 #ifdef CONFIG_FEATURE_SUN_LABEL
5863                         else if (label_sun == current_label_type)
5864                                 toggle_sunflags(get_partition(1, partitions),
5865                                                 0x10);
5866 #endif
5867 #ifdef CONFIG_FEATURE_SGI_LABEL
5868                         else if (label_sgi == current_label_type)
5869                                 sgi_set_swappartition(
5870                                                 get_partition(1, partitions));
5871 #endif
5872                         else
5873                                 unknown_command(c);
5874                         break;
5875                 case 'd':
5876                         {
5877                                 int j;
5878 #ifdef CONFIG_FEATURE_SGI_LABEL
5879                         /* If sgi_label then don't use get_existing_partition,
5880                            let the user select a partition, since
5881                            get_existing_partition() only works for Linux-like
5882                            partition tables */
5883                                 if (label_sgi != current_label_type) {
5884                                         j = get_existing_partition(1, partitions);
5885                                 } else {
5886                                         j = get_partition(1, partitions);
5887                                 }
5888 #else
5889                                 j = get_existing_partition(1, partitions);
5890 #endif
5891                                 if (j >= 0)
5892                                         delete_partition(j);
5893                         }
5894                         break;
5895                 case 'i':
5896 #ifdef CONFIG_FEATURE_SGI_LABEL
5897                         if (label_sgi == current_label_type)
5898                                 create_sgiinfo();
5899                         else
5900 #endif
5901                                 unknown_command(c);
5902                 case 'l':
5903                         list_types(get_sys_types());
5904                         break;
5905                 case 'm':
5906                         menu();
5907                         break;
5908                 case 'n':
5909                         new_partition();
5910                         break;
5911                 case 'o':
5912                         create_doslabel();
5913                         break;
5914                 case 'p':
5915                         list_table(0);
5916                         break;
5917                 case 'q':
5918                         close(fd);
5919                         printf("\n");
5920                         return 0;
5921                 case 's':
5922 #ifdef CONFIG_FEATURE_SUN_LABEL
5923                         create_sunlabel();
5924 #endif
5925                         break;
5926                 case 't':
5927                         change_sysid();
5928                         break;
5929                 case 'u':
5930                         change_units();
5931                         break;
5932                 case 'v':
5933                         verify();
5934                         break;
5935                 case 'w':
5936                         write_table();          /* does not return */
5937                         break;
5938 #ifdef CONFIG_FEATURE_FDISK_ADVANCED
5939                 case 'x':
5940 #ifdef CONFIG_FEATURE_SGI_LABEL
5941                         if (label_sgi == current_label_type) {
5942                                 fprintf(stderr,
5943                                         _("\n\tSorry, no experts menu for SGI "
5944                                         "partition tables available.\n\n"));
5945                         } else
5946 #endif
5947
5948                                 xselect();
5949                         break;
5950 #endif
5951                 default:
5952                         unknown_command(c);
5953                         menu();
5954                 }
5955         }
5956         return 0;
5957 #endif /* CONFIG_FEATURE_FDISK_WRITABLE */
5958 }