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