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