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