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