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