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