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