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