source: MondoRescue/trunk/mindi-busybox/util-linux/fdisk.c@ 956

Last change on this file since 956 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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