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