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