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