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