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