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