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