blob: c0828431a6ee38158e0fa32e75dd7950b39602de [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)
Mike Frysinger983e0ca2006-02-25 07:42:02 +00004 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005 *
Rob Landleyb73451d2006-02-24 16:29:00 +00006 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00007 */
8
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +00009/* Current changes have not compatibility with this version */
Eric Andersen99a75d12003-08-08 20:04:56 +000010#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000011
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000012
Rob Landley15d20a02006-05-29 05:00:44 +000013#define _(x) x
14
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000015#define PROC_PARTITIONS "/proc/partitions"
16
Eric Andersen256c4fd2004-05-19 09:00:00 +000017#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000018#include <sys/types.h>
19#include <sys/stat.h> /* stat */
20#include <ctype.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <errno.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <setjmp.h>
28#include <assert.h> /* assert */
29#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000031#include <sys/ioctl.h>
32#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000033#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000034
Eric Andersenacd244a2002-12-11 03:49:33 +000035#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
36
37/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000038#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000039
40#include <sys/utsname.h>
41
42#include "busybox.h"
43
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000044#define DKTYPENAMES
45
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000046/*
47 fdisk.h
48*/
49
50#define DEFAULT_SECTOR_SIZE 512
51#define MAX_SECTOR_SIZE 2048
52#define SECTOR_SIZE 512 /* still used in BSD code */
53#define MAXIMUM_PARTS 60
54
55#define ACTIVE_FLAG 0x80
56
57#define EXTENDED 0x05
58#define WIN98_EXTENDED 0x0f
59#define LINUX_PARTITION 0x81
60#define LINUX_SWAP 0x82
61#define LINUX_NATIVE 0x83
62#define LINUX_EXTENDED 0x85
63#define LINUX_LVM 0x8e
64#define LINUX_RAID 0xfd
65
66#define SUNOS_SWAP 3
67#define WHOLE_DISK 5
68
69#define IS_EXTENDED(i) \
70 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
71
72#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
73
74#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
75#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
76
Eric Andersen7495b0d2004-02-06 05:26:58 +000077#ifdef CONFIG_FEATURE_SUN_LABEL
78#define SCSI_IOCTL_GET_IDLUN 0x5382
79#endif
80
Eric Andersend3652bf2003-08-06 09:07:37 +000081
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000082/* including <linux/hdreg.h> also fails */
83struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000084 unsigned char heads;
85 unsigned char sectors;
86 unsigned short cylinders;
87 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000088};
89
90#define HDIO_GETGEO 0x0301 /* get device geometry */
91
92
93struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +000094 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000095};
96
Rob Landleyb73451d2006-02-24 16:29:00 +000097static uint sector_size = DEFAULT_SECTOR_SIZE;
98static uint user_set_sector_size;
99static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000100
101/*
102 * Raw disk label. For DOS-type partition tables the MBR,
103 * with descriptions of the primary partitions.
104 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000105#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000106static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000107#else
108# define MBRbuffer bb_common_bufsiz1
109#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000110
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000111#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000112static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000113#endif
114
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000115static uint heads, sectors, cylinders;
116static void update_units(void);
117
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000118
119/*
120 * return partition name - uses static storage unless buf is supplied
121 */
122static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000123partname(const char *dev, int pno, int lth)
124{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000125 static char buffer[80];
126 const char *p;
127 int w, wp;
128 int bufsiz;
129 char *bufp;
130
131 bufp = buffer;
132 bufsiz = sizeof(buffer);
133
134 w = strlen(dev);
135 p = "";
136
137 if (isdigit(dev[w-1]))
138 p = "p";
139
140 /* devfs kludge - note: fdisk partition names are not supposed
141 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000142 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000143 w -= 4;
144 p = "part";
145 }
146
147 wp = strlen(p);
148
149 if (lth) {
150 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
151 lth-wp-2, w, dev, p, pno);
152 } else {
153 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
154 }
155 return bufp;
156}
157
158struct partition {
159 unsigned char boot_ind; /* 0x80 - active */
160 unsigned char head; /* starting head */
161 unsigned char sector; /* starting sector */
162 unsigned char cyl; /* starting cylinder */
163 unsigned char sys_ind; /* What partition type */
164 unsigned char end_head; /* end head */
165 unsigned char end_sector; /* end sector */
166 unsigned char end_cyl; /* end cylinder */
167 unsigned char start4[4]; /* starting sector counting from 0 */
168 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000169} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000170
171enum failure {
172 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
173 unable_to_write
174};
175
Rob Landley5527b912006-02-25 03:46:10 +0000176enum label_type{
177 label_dos, label_sun, label_sgi, label_aix, label_osf
178};
179
Rob Landleyb73451d2006-02-24 16:29:00 +0000180enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000181
Rob Landley5527b912006-02-25 03:46:10 +0000182static enum label_type current_label_type;
183
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000184static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000185static int fd; /* the disk */
186static int partitions = 4; /* maximum partition + 1 */
187static uint display_in_cyl_units = 1;
188static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000189#ifdef CONFIG_FEATURE_FDISK_WRITABLE
190static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000191static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000192static void reread_partition_table(int leave);
193static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000194static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000195static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000196static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000197#endif
198static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000199static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000200static void get_geometry(void);
201static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000202
203#define PLURAL 0
204#define SINGULAR 1
205
206#define hex_val(c) ({ \
207 char _c = (c); \
208 isdigit(_c) ? _c - '0' : \
209 tolower(_c) + 10 - 'a'; \
210 })
211
212
213#define LINE_LENGTH 800
214#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
215 (n) * sizeof(struct partition)))
216#define sector(s) ((s) & 0x3f)
217#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
218
219#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
220 ((h) + heads * cylinder(s,c)))
221#define set_hsc(h,s,c,sector) { \
222 s = sector % sectors + 1; \
223 sector /= sectors; \
224 h = sector % heads; \
225 sector /= heads; \
226 c = sector & 0xff; \
227 s |= (sector >> 2) & 0xc0; \
228 }
229
230
Eric Andersend9261492004-06-28 23:50:31 +0000231static int32_t get_start_sect(const struct partition *p);
232static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000233
234/*
235 * per partition table entry data
236 *
237 * The four primary partitions have the same sectorbuffer (MBRbuffer)
238 * and have NULL ext_pointer.
239 * Each logical partition table entry has two pointers, one for the
240 * partition and one link to the next one.
241 */
242static struct pte {
243 struct partition *part_table; /* points into sectorbuffer */
244 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000245#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000246 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000247#endif
Eric Andersend9261492004-06-28 23:50:31 +0000248 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000249 char *sectorbuffer; /* disk sector contents */
250} ptes[MAXIMUM_PARTS];
251
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000252
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000253#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000254static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000255set_all_unchanged(void)
256{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000257 int i;
258
259 for (i = 0; i < MAXIMUM_PARTS; i++)
260 ptes[i].changed = 0;
261}
262
263static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000264set_changed(int i)
265{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000266 ptes[i].changed = 1;
267}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000268#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000269
270#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
271static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000272get_part_table(int i)
273{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000274 return ptes[i].part_table;
275}
276#endif
277
278static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000279str_units(int n)
280{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000281 if (n == 1)
282 return display_in_cyl_units ? _("cylinder") : _("sector");
283 else
284 return display_in_cyl_units ? _("cylinders") : _("sectors");
285}
286
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000287static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000288valid_part_table_flag(const char *mbuffer) {
289 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000290 return (b[510] == 0x55 && b[511] == 0xaa);
291}
292
293#ifdef CONFIG_FEATURE_FDISK_WRITABLE
294static char line_buffer[LINE_LENGTH];
295
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000296/* read line; return 0 or first char */
297static int
298read_line(void)
299{
300 static int got_eof = 0;
301
302 fflush (stdout); /* requested by niles@scyld.com */
303 line_ptr = line_buffer;
304 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
305 if (feof(stdin))
306 got_eof++; /* user typed ^D ? */
307 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000308 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
309 exit(1);
310 }
311 return 0;
312 }
313 while (*line_ptr && !isgraph(*line_ptr))
314 line_ptr++;
315 return *line_ptr;
316}
317
318static char
319read_char(const char *mesg)
320{
321 do {
322 fputs(mesg, stdout);
323 } while (!read_line());
324 return *line_ptr;
325}
326
327static char
328read_chars(const char *mesg)
329{
330 fputs(mesg, stdout);
331 if (!read_line()) {
332 *line_ptr = '\n';
333 line_ptr[1] = 0;
334 }
335 return *line_ptr;
336}
337
338static int
339read_hex(const struct systypes *sys)
340{
341 int hex;
342
Rob Landleyb73451d2006-02-24 16:29:00 +0000343 while (1) {
344 read_char(_("Hex code (type L to list codes): "));
345 if (*line_ptr == 'l' || *line_ptr == 'L')
346 list_types(sys);
347 else if (isxdigit (*line_ptr)) {
348 hex = 0;
349 do
350 hex = hex << 4 | hex_val(*line_ptr++);
351 while (isxdigit(*line_ptr));
352 return hex;
353 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000354 }
355}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000356#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000357
358#ifdef CONFIG_FEATURE_AIX_LABEL
359/*
360 * Copyright (C) Andreas Neuper, Sep 1998.
361 * This file may be redistributed under
362 * the terms of the GNU Public License.
363 */
364
365typedef struct {
366 unsigned int magic; /* expect AIX_LABEL_MAGIC */
367 unsigned int fillbytes1[124];
368 unsigned int physical_volume_id;
369 unsigned int fillbytes2[124];
370} aix_partition;
371
372#define AIX_LABEL_MAGIC 0xc9c2d4c1
373#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
374#define AIX_INFO_MAGIC 0x00072959
375#define AIX_INFO_MAGIC_SWAPPED 0x59290700
376
377#define aixlabel ((aix_partition *)MBRbuffer)
378
379
380/*
381 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000382 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
383 * Internationalization
384 *
385 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
386 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000387*/
388
Rob Landleyb73451d2006-02-24 16:29:00 +0000389static int aix_other_endian;
390static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000391
392/*
393 * only dealing with free blocks here
394 */
395
396static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000397aix_info(void)
398{
399 puts(
400 _("\n\tThere is a valid AIX label on this disk.\n"
401 "\tUnfortunately Linux cannot handle these\n"
402 "\tdisks at the moment. Nevertheless some\n"
403 "\tadvice:\n"
404 "\t1. fdisk will destroy its contents on write.\n"
405 "\t2. Be sure that this disk is NOT a still vital\n"
406 "\t part of a volume group. (Otherwise you may\n"
407 "\t erase the other disks as well, if unmirrored.)\n"
408 "\t3. Before deleting this physical volume be sure\n"
409 "\t to remove the disk logically from your AIX\n"
410 "\t machine. (Otherwise you become an AIXpert).")
411 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000412}
413
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000414static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000415check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000416{
Rob Landleyb73451d2006-02-24 16:29:00 +0000417 if (aixlabel->magic != AIX_LABEL_MAGIC &&
418 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000419 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000420 aix_other_endian = 0;
421 return 0;
422 }
423 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
424 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000425 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000426 partitions = 1016;
427 aix_volumes = 15;
428 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000429 /*aix_nolabel();*/ /* %% */
430 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000431 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000432}
433#endif /* AIX_LABEL */
434
435#ifdef CONFIG_FEATURE_OSF_LABEL
436/*
437 * Copyright (c) 1987, 1988 Regents of the University of California.
438 * All rights reserved.
439 *
440 * Redistribution and use in source and binary forms, with or without
441 * modification, are permitted provided that the following conditions
442 * are met:
443 * 1. Redistributions of source code must retain the above copyright
444 * notice, this list of conditions and the following disclaimer.
445 * 2. Redistributions in binary form must reproduce the above copyright
446 * notice, this list of conditions and the following disclaimer in the
447 * documentation and/or other materials provided with the distribution.
448 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000449 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000450 * This product includes software developed by the University of
451 * California, Berkeley and its contributors.
452 * 4. Neither the name of the University nor the names of its contributors
453 * may be used to endorse or promote products derived from this software
454 * without specific prior written permission.
455 *
456 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
457 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
458 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
459 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
460 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
461 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
462 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
463 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
464 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
465 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
466 * SUCH DAMAGE.
467 */
468
469
470#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000471#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000472#endif
473
474#ifndef BSD_MAXPARTITIONS
475#define BSD_MAXPARTITIONS 16
476#endif
477
478#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
479
Mike Frysingerc340ea12006-06-30 02:53:56 +0000480#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__m68k__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000481#define BSD_LABELSECTOR 1
482#define BSD_LABELOFFSET 0
483#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
484#define BSD_LABELSECTOR 0
485#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000486#elif defined (__s390__) || defined (__s390x__)
487#define BSD_LABELSECTOR 1
488#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000489#else
490#error unknown architecture
491#endif
492
493#define BSD_BBSIZE 8192 /* size of boot area, with label */
494#define BSD_SBSIZE 8192 /* max size of fs superblock */
495
496struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000497 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000498 int16_t d_type; /* drive type */
499 int16_t d_subtype; /* controller/d_type specific */
500 char d_typename[16]; /* type name, e.g. "eagle" */
501 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000502 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000503 uint32_t d_secsize; /* # of bytes per sector */
504 uint32_t d_nsectors; /* # of data sectors per track */
505 uint32_t d_ntracks; /* # of tracks per cylinder */
506 uint32_t d_ncylinders; /* # of data cylinders per unit */
507 uint32_t d_secpercyl; /* # of data sectors per cylinder */
508 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000509 /*
510 * Spares (bad sector replacements) below
511 * are not counted in d_nsectors or d_secpercyl.
512 * Spare sectors are assumed to be physical sectors
513 * which occupy space at the end of each track and/or cylinder.
514 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000515 uint16_t d_sparespertrack; /* # of spare sectors per track */
516 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000517 /*
518 * Alternate cylinders include maintenance, replacement,
519 * configuration description areas, etc.
520 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000521 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000522
523 /* hardware characteristics: */
524 /*
525 * d_interleave, d_trackskew and d_cylskew describe perturbations
526 * in the media format used to compensate for a slow controller.
527 * Interleave is physical sector interleave, set up by the formatter
528 * or controller when formatting. When interleaving is in use,
529 * logically adjacent sectors are not physically contiguous,
530 * but instead are separated by some number of sectors.
531 * It is specified as the ratio of physical sectors traversed
532 * per logical sector. Thus an interleave of 1:1 implies contiguous
533 * layout, while 2:1 implies that logical sector 0 is separated
534 * by one sector from logical sector 1.
535 * d_trackskew is the offset of sector 0 on track N
536 * relative to sector 0 on track N-1 on the same cylinder.
537 * Finally, d_cylskew is the offset of sector 0 on cylinder N
538 * relative to sector 0 on cylinder N-1.
539 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000540 uint16_t d_rpm; /* rotational speed */
541 uint16_t d_interleave; /* hardware sector interleave */
542 uint16_t d_trackskew; /* sector 0 skew, per track */
543 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
544 uint32_t d_headswitch; /* head switch time, usec */
545 uint32_t d_trkseek; /* track-to-track seek, usec */
546 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000547#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000548 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000549#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000550 uint32_t d_spare[NSPARE]; /* reserved for future use */
551 uint32_t d_magic2; /* the magic number (again) */
552 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000553 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000554 uint16_t d_npartitions; /* number of partitions in following */
555 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
556 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000557 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000558 uint32_t p_size; /* number of sectors in partition */
559 uint32_t p_offset; /* starting sector */
560 uint32_t p_fsize; /* filesystem basic fragment size */
561 uint8_t p_fstype; /* filesystem type, see below */
562 uint8_t p_frag; /* filesystem fragments per block */
563 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000564 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
565};
566
567/* d_type values: */
568#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
569#define BSD_DTYPE_MSCP 2 /* MSCP */
570#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
571#define BSD_DTYPE_SCSI 4 /* SCSI */
572#define BSD_DTYPE_ESDI 5 /* ESDI interface */
573#define BSD_DTYPE_ST506 6 /* ST506 etc. */
574#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
575#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
576#define BSD_DTYPE_FLOPPY 10 /* floppy */
577
578/* d_subtype values: */
579#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
580#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
581#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
582
583#ifdef DKTYPENAMES
584static const char * const xbsd_dktypenames[] = {
585 "unknown",
586 "SMD",
587 "MSCP",
588 "old DEC",
589 "SCSI",
590 "ESDI",
591 "ST506",
592 "HP-IB",
593 "HP-FL",
594 "type 9",
595 "floppy",
596 0
597};
598#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
599#endif
600
601/*
602 * Filesystem type and version.
603 * Used to interpret other filesystem-specific
604 * per-partition information.
605 */
606#define BSD_FS_UNUSED 0 /* unused */
607#define BSD_FS_SWAP 1 /* swap */
608#define BSD_FS_V6 2 /* Sixth Edition */
609#define BSD_FS_V7 3 /* Seventh Edition */
610#define BSD_FS_SYSV 4 /* System V */
611#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
612#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
613#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
614#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
615#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
616#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
617#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
618#define BSD_FS_ISOFS BSD_FS_ISO9660
619#define BSD_FS_BOOT 13 /* partition contains bootstrap */
620#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
621#define BSD_FS_HFS 15 /* Macintosh HFS */
622#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
623
624/* this is annoying, but it's also the way it is :-( */
625#ifdef __alpha__
626#define BSD_FS_EXT2 8 /* ext2 file system */
627#else
628#define BSD_FS_MSDOS 8 /* MS-DOS file system */
629#endif
630
631#ifdef DKTYPENAMES
632static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000633 { "\x00" "unused" }, /* BSD_FS_UNUSED */
634 { "\x01" "swap" }, /* BSD_FS_SWAP */
635 { "\x02" "Version 6" }, /* BSD_FS_V6 */
636 { "\x03" "Version 7" }, /* BSD_FS_V7 */
637 { "\x04" "System V" }, /* BSD_FS_SYSV */
638 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
639 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
640 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000641#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000642 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000643#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000644 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000645#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000646 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
647 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
648 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
649 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
650 { "\x0d" "boot" }, /* BSD_FS_BOOT */
651 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
652 { "\x0f" "HFS" }, /* BSD_FS_HFS */
653 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
654 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000655};
656#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
657
658#endif
659
660/*
661 * flags shared by various drives:
662 */
663#define BSD_D_REMOVABLE 0x01 /* removable media */
664#define BSD_D_ECC 0x02 /* supports ECC */
665#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
666#define BSD_D_RAMDISK 0x08 /* disk emulator */
667#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
668#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
669
670#endif /* OSF_LABEL */
671
672/*
673 * Copyright (C) Andreas Neuper, Sep 1998.
674 * This file may be modified and redistributed under
675 * the terms of the GNU Public License.
676 */
677
678struct device_parameter { /* 48 bytes */
679 unsigned char skew;
680 unsigned char gap1;
681 unsigned char gap2;
682 unsigned char sparecyl;
683 unsigned short pcylcount;
684 unsigned short head_vol0;
685 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
686 unsigned char cmd_tag_queue_depth;
687 unsigned char unused0;
688 unsigned short unused1;
689 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
690 unsigned short bytes;
691 unsigned short ilfact;
692 unsigned int flags; /* controller flags */
693 unsigned int datarate;
694 unsigned int retries_on_error;
695 unsigned int ms_per_word;
696 unsigned short xylogics_gap1;
697 unsigned short xylogics_syncdelay;
698 unsigned short xylogics_readdelay;
699 unsigned short xylogics_gap2;
700 unsigned short xylogics_readgate;
701 unsigned short xylogics_writecont;
702};
703
704#define SGI_VOLHDR 0x00
705/* 1 and 2 were used for drive types no longer supported by SGI */
706#define SGI_SWAP 0x03
707/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
708#define SGI_VOLUME 0x06
709#define SGI_EFS 0x07
710#define SGI_LVOL 0x08
711#define SGI_RLVOL 0x09
712#define SGI_XFS 0x0a
713#define SGI_XFSLOG 0x0b
714#define SGI_XLV 0x0c
715#define SGI_XVM 0x0d
716#define ENTIRE_DISK SGI_VOLUME
717/*
718 * controller flags
719 */
720#define SECTOR_SLIP 0x01
721#define SECTOR_FWD 0x02
722#define TRACK_FWD 0x04
723#define TRACK_MULTIVOL 0x08
724#define IGNORE_ERRORS 0x10
725#define RESEEK 0x20
726#define ENABLE_CMDTAGQ 0x40
727
728typedef struct {
729 unsigned int magic; /* expect SGI_LABEL_MAGIC */
730 unsigned short boot_part; /* active boot partition */
731 unsigned short swap_part; /* active swap partition */
732 unsigned char boot_file[16]; /* name of the bootfile */
733 struct device_parameter devparam; /* 1 * 48 bytes */
734 struct volume_directory { /* 15 * 16 bytes */
735 unsigned char vol_file_name[8]; /* a character array */
736 unsigned int vol_file_start; /* number of logical block */
737 unsigned int vol_file_size; /* number of bytes */
738 } directory[15];
739 struct sgi_partition { /* 16 * 12 bytes */
740 unsigned int num_sectors; /* number of blocks */
741 unsigned int start_sector; /* must be cylinder aligned */
742 unsigned int id;
743 } partitions[16];
744 unsigned int csum;
745 unsigned int fillbytes;
746} sgi_partition;
747
748typedef struct {
749 unsigned int magic; /* looks like a magic number */
750 unsigned int a2;
751 unsigned int a3;
752 unsigned int a4;
753 unsigned int b1;
754 unsigned short b2;
755 unsigned short b3;
756 unsigned int c[16];
757 unsigned short d[3];
758 unsigned char scsi_string[50];
759 unsigned char serial[137];
760 unsigned short check1816;
761 unsigned char installer[225];
762} sgiinfo;
763
764#define SGI_LABEL_MAGIC 0x0be5a941
765#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
766#define SGI_INFO_MAGIC 0x00072959
767#define SGI_INFO_MAGIC_SWAPPED 0x59290700
768#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000769 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000770#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000771 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000772
773#define sgilabel ((sgi_partition *)MBRbuffer)
774#define sgiparam (sgilabel->devparam)
775
776typedef struct {
777 unsigned char info[128]; /* Informative text string */
778 unsigned char spare0[14];
779 struct sun_info {
780 unsigned char spare1;
781 unsigned char id;
782 unsigned char spare2;
783 unsigned char flags;
784 } infos[8];
785 unsigned char spare1[246]; /* Boot information etc. */
786 unsigned short rspeed; /* Disk rotational speed */
787 unsigned short pcylcount; /* Physical cylinder count */
788 unsigned short sparecyl; /* extra sects per cylinder */
789 unsigned char spare2[4]; /* More magic... */
790 unsigned short ilfact; /* Interleave factor */
791 unsigned short ncyl; /* Data cylinder count */
792 unsigned short nacyl; /* Alt. cylinder count */
793 unsigned short ntrks; /* Tracks per cylinder */
794 unsigned short nsect; /* Sectors per track */
795 unsigned char spare3[4]; /* Even more magic... */
796 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000797 uint32_t start_cylinder;
798 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000799 } partitions[8];
800 unsigned short magic; /* Magic number */
801 unsigned short csum; /* Label xor'd checksum */
802} sun_partition;
803
Eric Andersen040f4402003-07-30 08:40:37 +0000804
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000805#define SUN_LABEL_MAGIC 0xDABE
806#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
807#define sunlabel ((sun_partition *)MBRbuffer)
808#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000809 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000810#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000811 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000812
Eric Andersend3652bf2003-08-06 09:07:37 +0000813
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000814#ifdef CONFIG_FEATURE_OSF_LABEL
815/*
816 Changes:
817 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
818
819 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
820 support for OSF/1 disklabels on Alpha.
821 Also fixed unaligned accesses in alpha_bootblock_checksum()
822*/
823
824#define FREEBSD_PARTITION 0xa5
825#define NETBSD_PARTITION 0xa9
826
Rob Landleyb73451d2006-02-24 16:29:00 +0000827static void xbsd_delete_part(void);
828static void xbsd_new_part(void);
829static void xbsd_write_disklabel(void);
830static int xbsd_create_disklabel(void);
831static void xbsd_edit_disklabel(void);
832static void xbsd_write_bootstrap(void);
833static void xbsd_change_fstype(void);
834static int xbsd_get_part_index(int max);
835static int xbsd_check_new_partition(int *i);
836static void xbsd_list_types(void);
837static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
838static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
839static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
840static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000841
842#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000843static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000844#endif
845
846#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000847static int xbsd_translate_fstype(int linux_type);
848static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000849static struct partition *xbsd_part;
850static int xbsd_part_index;
851#endif
852
853#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000854/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000855static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000856#else
857static char disklabelbuffer[BSD_BBSIZE];
858#endif
859
860static struct xbsd_disklabel xbsd_dlabel;
861
862#define bsd_cround(n) \
863 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
864
865/*
866 * Test whether the whole disk has BSD disk label magic.
867 *
868 * Note: often reformatting with DOS-type label leaves the BSD magic,
869 * so this does not mean that there is a BSD disk label.
870 */
871static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000872check_osf_label(void)
873{
874 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000875 return 0;
876 return 1;
877}
878
879static void xbsd_print_disklabel(int);
880
881static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000882btrydev(const char * dev)
883{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000884 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
885 return -1;
886 printf(_("\nBSD label for device: %s\n"), dev);
887 xbsd_print_disklabel (0);
888 return 0;
889}
890
891static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000892bmenu(void)
893{
894 puts (_("Command action"));
895 puts (_("\td\tdelete a BSD partition"));
896 puts (_("\te\tedit drive data"));
897 puts (_("\ti\tinstall bootstrap"));
898 puts (_("\tl\tlist known filesystem types"));
899 puts (_("\tm\tprint this menu"));
900 puts (_("\tn\tadd a new BSD partition"));
901 puts (_("\tp\tprint BSD partition table"));
902 puts (_("\tq\tquit without saving changes"));
903 puts (_("\tr\treturn to main menu"));
904 puts (_("\ts\tshow complete disklabel"));
905 puts (_("\tt\tchange a partition's filesystem id"));
906 puts (_("\tu\tchange units (cylinders/sectors)"));
907 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000908#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000909 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000910#endif
911}
912
913#if !defined (__alpha__)
914static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000915hidden(int type)
916{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000917 return type ^ 0x10;
918}
919
920static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000921is_bsd_partition_type(int type)
922{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000923 return (type == FREEBSD_PARTITION ||
924 type == hidden(FREEBSD_PARTITION) ||
925 type == NETBSD_PARTITION ||
926 type == hidden(NETBSD_PARTITION));
927}
928#endif
929
930static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000931bselect(void)
932{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000933#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000934 int t, ss;
935 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000936
Rob Landleyb73451d2006-02-24 16:29:00 +0000937 for (t = 0; t < 4; t++) {
938 p = get_part_table(t);
939 if (p && is_bsd_partition_type(p->sys_ind)) {
940 xbsd_part = p;
941 xbsd_part_index = t;
942 ss = get_start_sect(xbsd_part);
943 if (ss == 0) {
944 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
945 partname(disk_device, t+1, 0));
946 return;
947 }
948 printf(_("Reading disklabel of %s at sector %d.\n"),
949 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
950 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
951 if (xbsd_create_disklabel() == 0)
952 return;
953 break;
954 }
955 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000956
Rob Landleyb73451d2006-02-24 16:29:00 +0000957 if (t == 4) {
958 printf(_("There is no *BSD partition on %s.\n"), disk_device);
959 return;
960 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000961
962#elif defined (__alpha__)
963
Rob Landleyb73451d2006-02-24 16:29:00 +0000964 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
965 if (xbsd_create_disklabel() == 0)
966 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000967
968#endif
969
Rob Landleyb73451d2006-02-24 16:29:00 +0000970 while (1) {
971 putchar('\n');
972 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
973 case 'd':
974 xbsd_delete_part();
975 break;
976 case 'e':
977 xbsd_edit_disklabel();
978 break;
979 case 'i':
980 xbsd_write_bootstrap();
981 break;
982 case 'l':
983 xbsd_list_types();
984 break;
985 case 'n':
986 xbsd_new_part();
987 break;
988 case 'p':
989 xbsd_print_disklabel(0);
990 break;
991 case 'q':
992 close(fd);
993 exit(EXIT_SUCCESS);
994 case 'r':
995 return;
996 case 's':
997 xbsd_print_disklabel(1);
998 break;
999 case 't':
1000 xbsd_change_fstype();
1001 break;
1002 case 'u':
1003 change_units();
1004 break;
1005 case 'w':
1006 xbsd_write_disklabel();
1007 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001008#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001009 case 'x':
1010 xbsd_link_part();
1011 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001012#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001013 default:
1014 bmenu();
1015 break;
1016 }
1017 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001018}
1019
1020static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001021xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001022{
Rob Landleyb73451d2006-02-24 16:29:00 +00001023 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001024
Rob Landleyb73451d2006-02-24 16:29:00 +00001025 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1026 xbsd_dlabel.d_partitions[i].p_size = 0;
1027 xbsd_dlabel.d_partitions[i].p_offset = 0;
1028 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1029 if (xbsd_dlabel.d_npartitions == i + 1)
1030 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1031 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001032}
1033
1034static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001035xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001036{
Rob Landleyb73451d2006-02-24 16:29:00 +00001037 off_t begin, end;
1038 char mesg[256];
1039 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001040
Rob Landleyb73451d2006-02-24 16:29:00 +00001041 if (!xbsd_check_new_partition(&i))
1042 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001043
1044#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001045 begin = get_start_sect(xbsd_part);
1046 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001047#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001048 begin = 0;
1049 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001050#endif
1051
Rob Landleyb73451d2006-02-24 16:29:00 +00001052 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1053 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1054 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001055
Rob Landleyb73451d2006-02-24 16:29:00 +00001056 if (display_in_cyl_units)
1057 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001058
Rob Landleyb73451d2006-02-24 16:29:00 +00001059 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1060 str_units(SINGULAR));
1061 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1062 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001063
Rob Landleyb73451d2006-02-24 16:29:00 +00001064 if (display_in_cyl_units)
1065 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001066
Rob Landleyb73451d2006-02-24 16:29:00 +00001067 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1068 xbsd_dlabel.d_partitions[i].p_offset = begin;
1069 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001070}
1071
1072static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001073xbsd_print_disklabel(int show_all)
1074{
1075 struct xbsd_disklabel *lp = &xbsd_dlabel;
1076 struct xbsd_partition *pp;
1077 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001078
Rob Landleyb73451d2006-02-24 16:29:00 +00001079 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001080#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001081 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001082#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001083 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001084#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001085 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1086 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1087 else
1088 printf(_("type: %d\n"), lp->d_type);
1089 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1090 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1091 printf(_("flags:"));
1092 if (lp->d_flags & BSD_D_REMOVABLE)
1093 printf(_(" removable"));
1094 if (lp->d_flags & BSD_D_ECC)
1095 printf(_(" ecc"));
1096 if (lp->d_flags & BSD_D_BADSECT)
1097 printf(_(" badsect"));
1098 printf("\n");
1099 /* On various machines the fields of *lp are short/int/long */
1100 /* In order to avoid problems, we cast them all to long. */
1101 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1102 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1103 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1104 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1105 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1106 printf(_("rpm: %d\n"), lp->d_rpm);
1107 printf(_("interleave: %d\n"), lp->d_interleave);
1108 printf(_("trackskew: %d\n"), lp->d_trackskew);
1109 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1110 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1111 (long) lp->d_headswitch);
1112 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1113 (long) lp->d_trkseek);
1114 printf(_("drivedata: "));
1115 for (i = NDDATA - 1; i >= 0; i--)
1116 if (lp->d_drivedata[i])
1117 break;
1118 if (i < 0)
1119 i = 0;
1120 for (j = 0; j <= i; j++)
1121 printf("%ld ", (long) lp->d_drivedata[j]);
1122 }
1123 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1124 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1125 pp = lp->d_partitions;
1126 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1127 if (pp->p_size) {
1128 if (display_in_cyl_units && lp->d_secpercyl) {
1129 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1130 'a' + i,
1131 (long) pp->p_offset / lp->d_secpercyl + 1,
1132 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1133 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1134 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1135 (long) pp->p_size / lp->d_secpercyl,
1136 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1137 );
1138 } else {
1139 printf(" %c: %8ld %8ld %8ld ",
1140 'a' + i,
1141 (long) pp->p_offset,
1142 (long) pp->p_offset + pp->p_size - 1,
1143 (long) pp->p_size
1144 );
1145 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001146
Rob Landleyb73451d2006-02-24 16:29:00 +00001147 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1148 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1149 else
1150 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001151
Rob Landleyb73451d2006-02-24 16:29:00 +00001152 switch (pp->p_fstype) {
1153 case BSD_FS_UNUSED:
1154 printf(" %5ld %5ld %5.5s ",
1155 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1156 break;
1157 case BSD_FS_BSDFFS:
1158 printf(" %5ld %5ld %5d ",
1159 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1160 break;
1161 default:
1162 printf("%22.22s", "");
1163 break;
1164 }
1165 printf("\n");
1166 }
1167 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001168}
1169
1170static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001171xbsd_write_disklabel(void)
1172{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001173#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001174 printf(_("Writing disklabel to %s.\n"), disk_device);
1175 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001176#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001177 printf(_("Writing disklabel to %s.\n"),
1178 partname(disk_device, xbsd_part_index + 1, 0));
1179 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001180#endif
1181 reread_partition_table(0); /* no exit yet */
1182}
1183
1184static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001185xbsd_create_disklabel(void)
1186{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001187 char c;
1188
1189#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001190 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001191#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001192 fprintf(stderr, _("%s contains no disklabel.\n"),
1193 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001194#endif
1195
1196 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001197 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001198 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001199 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001200#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001201 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001202 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001203#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001204 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001205#endif
1206 ) == 1) {
1207 xbsd_print_disklabel (1);
1208 return 1;
1209 } else
1210 return 0;
1211 } else if (c == 'n')
1212 return 0;
1213 }
1214}
1215
1216static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001217edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001218{
Rob Landleyb73451d2006-02-24 16:29:00 +00001219 do {
1220 fputs(mesg, stdout);
1221 printf(" (%d): ", def);
1222 if (!read_line())
1223 return def;
1224 }
1225 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1226 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001227}
1228
1229static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001230xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001231{
Rob Landleyb73451d2006-02-24 16:29:00 +00001232 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001233
Rob Landleyb73451d2006-02-24 16:29:00 +00001234 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001235
1236#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001237 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1238 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1239 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1240 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001241#endif
1242
Rob Landleyb73451d2006-02-24 16:29:00 +00001243 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1244 while (1) {
1245 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1246 _("sectors/cylinder"));
1247 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1248 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001249
Rob Landleyb73451d2006-02-24 16:29:00 +00001250 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1251 }
1252 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1253 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1254 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1255 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1256 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1257 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001258
Rob Landleyb73451d2006-02-24 16:29:00 +00001259 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001260}
1261
1262static int
1263xbsd_get_bootstrap (char *path, void *ptr, int size)
1264{
Rob Landleyb73451d2006-02-24 16:29:00 +00001265 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001266
Rob Landleyb73451d2006-02-24 16:29:00 +00001267 if ((fdb = open (path, O_RDONLY)) < 0) {
1268 perror(path);
1269 return 0;
1270 }
1271 if (read(fdb, ptr, size) < 0) {
1272 perror(path);
1273 close(fdb);
1274 return 0;
1275 }
1276 printf(" ... %s\n", path);
1277 close(fdb);
1278 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001279}
1280
1281static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001282sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001283{
Rob Landleyb73451d2006-02-24 16:29:00 +00001284 printf(_("\nSyncing disks.\n"));
1285 sync();
1286 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001287}
1288
1289static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001290xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291{
Rob Landleyb73451d2006-02-24 16:29:00 +00001292 char *bootdir = BSD_LINUX_BOOTDIR;
1293 char path[MAXPATHLEN];
1294 char *dkbasename;
1295 struct xbsd_disklabel dl;
1296 char *d, *p, *e;
1297 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001298
Rob Landleyb73451d2006-02-24 16:29:00 +00001299 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1300 dkbasename = "sd";
1301 else
1302 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001303
Rob Landleyb73451d2006-02-24 16:29:00 +00001304 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1305 dkbasename, dkbasename, dkbasename);
1306 if (read_line()) {
1307 line_ptr[strlen(line_ptr)-1] = '\0';
1308 dkbasename = line_ptr;
1309 }
1310 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1311 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1312 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001313
Rob Landleyb73451d2006-02-24 16:29:00 +00001314/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1315 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
Mike Frysinger1a540302006-04-16 05:58:21 +00001316 memmove(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001317
Rob Landleyb73451d2006-02-24 16:29:00 +00001318/* The disklabel will be overwritten by 0's from bootxx anyway */
1319 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001320
Rob Landleyb73451d2006-02-24 16:29:00 +00001321 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1322 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001323 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001324 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001325
Rob Landleyb73451d2006-02-24 16:29:00 +00001326 e = d + sizeof(struct xbsd_disklabel);
1327 for (p = d; p < e; p++)
1328 if (*p) {
1329 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1330 exit(EXIT_FAILURE);
1331 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001332
Mike Frysinger1a540302006-04-16 05:58:21 +00001333 memmove(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001334
1335#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001336 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001337#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001338 sector = 0;
1339 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001340#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001341 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001342#endif
1343
Rob Landleyb73451d2006-02-24 16:29:00 +00001344 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1345 fdisk_fatal(unable_to_seek);
1346 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1347 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001348
1349#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001350 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001351#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001352 printf(_("Bootstrap installed on %s.\n"),
1353 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001354#endif
1355
Rob Landleyb73451d2006-02-24 16:29:00 +00001356 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001357}
1358
1359static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001360xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001361{
Rob Landleyb73451d2006-02-24 16:29:00 +00001362 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001363
Rob Landleyb73451d2006-02-24 16:29:00 +00001364 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1365 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001366}
1367
1368static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001369xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001370{
Rob Landleyb73451d2006-02-24 16:29:00 +00001371 char prompt[256];
1372 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373
Rob Landleyb73451d2006-02-24 16:29:00 +00001374 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1375 do
1376 l = tolower(read_char(prompt));
1377 while (l < 'a' || l > 'a' + max - 1);
1378 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001379}
1380
1381static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001382xbsd_check_new_partition(int *i)
1383{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001384 /* room for more? various BSD flavours have different maxima */
1385 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1386 int t;
1387
1388 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1389 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1390 break;
1391
1392 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001393 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001394 "has been created\n"));
1395 return 0;
1396 }
1397 }
1398
1399 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1400
1401 if (*i >= xbsd_dlabel.d_npartitions)
1402 xbsd_dlabel.d_npartitions = (*i) + 1;
1403
1404 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001405 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001406 return 0;
1407 }
1408
1409 return 1;
1410}
1411
1412static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001413xbsd_list_types(void)
1414{
1415 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001416}
1417
1418static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001419xbsd_dkcksum(struct xbsd_disklabel *lp)
1420{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001421 u_short *start, *end;
1422 u_short sum = 0;
1423
1424 start = (u_short *) lp;
1425 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1426 while (start < end)
1427 sum ^= *start++;
1428 return sum;
1429}
1430
1431static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001432xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1433{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001434 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001435
Rob Landleyb73451d2006-02-24 16:29:00 +00001436 get_geometry();
1437 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001438
Rob Landleyb73451d2006-02-24 16:29:00 +00001439 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001440
Rob Landleyb73451d2006-02-24 16:29:00 +00001441 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1442 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001443 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001444 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001445
1446#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001447 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001448#endif
1449
1450#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001451 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001452#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001453 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001454#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001455 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1456 d->d_nsectors = sectors; /* sectors/track */
1457 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1458 d->d_ncylinders = cylinders;
1459 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1460 if (d->d_secpercyl == 0)
1461 d->d_secpercyl = 1; /* avoid segfaults */
1462 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001463
Rob Landleyb73451d2006-02-24 16:29:00 +00001464 d->d_rpm = 3600;
1465 d->d_interleave = 1;
1466 d->d_trackskew = 0;
1467 d->d_cylskew = 0;
1468 d->d_headswitch = 0;
1469 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001470
Rob Landleyb73451d2006-02-24 16:29:00 +00001471 d->d_magic2 = BSD_DISKMAGIC;
1472 d->d_bbsize = BSD_BBSIZE;
1473 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001474
1475#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001476 d->d_npartitions = 4;
1477 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001478 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001479 pp->p_offset = get_start_sect(p);
1480 pp->p_size = get_nr_sects(p);
1481 pp->p_fstype = BSD_FS_UNUSED;
1482 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001483 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001484 pp->p_offset = 0;
1485 pp->p_size = d->d_secperunit;
1486 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001487#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001488 d->d_npartitions = 3;
1489 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001490 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001491 pp->p_offset = 0;
1492 pp->p_size = d->d_secperunit;
1493 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001494#endif
1495
1496 return 1;
1497}
1498
1499/*
1500 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1501 * If it has the right magic, return 1.
1502 */
1503static int
1504xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1505{
1506 int t, sector;
1507
1508 /* p is used only to get the starting sector */
1509#if !defined (__alpha__)
1510 sector = (p ? get_start_sect(p) : 0);
1511#elif defined (__alpha__)
1512 sector = 0;
1513#endif
1514
Rob Landleyb73451d2006-02-24 16:29:00 +00001515 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1516 fdisk_fatal(unable_to_seek);
1517 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1518 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001519
Mike Frysinger1a540302006-04-16 05:58:21 +00001520 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1521 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001522
Rob Landleyb73451d2006-02-24 16:29:00 +00001523 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001524 return 0;
1525
Rob Landleyb73451d2006-02-24 16:29:00 +00001526 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1527 d->d_partitions[t].p_size = 0;
1528 d->d_partitions[t].p_offset = 0;
1529 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001530 }
1531
Rob Landleyb73451d2006-02-24 16:29:00 +00001532 if (d->d_npartitions > BSD_MAXPARTITIONS)
1533 fprintf(stderr, _("Warning: too many partitions "
1534 "(%d, maximum is %d).\n"),
1535 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001536 return 1;
1537}
1538
1539static int
1540xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1541{
Rob Landleyb73451d2006-02-24 16:29:00 +00001542 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001543
1544#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001545 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001546#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001547 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001548#endif
1549
Rob Landleyb73451d2006-02-24 16:29:00 +00001550 d->d_checksum = 0;
1551 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001552
Rob Landleyb73451d2006-02-24 16:29:00 +00001553 /* This is necessary if we want to write the bootstrap later,
1554 otherwise we'd write the old disklabel with the bootstrap.
1555 */
Mike Frysinger1a540302006-04-16 05:58:21 +00001556 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1557 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001558
1559#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001560 alpha_bootblock_checksum (disklabelbuffer);
1561 if (lseek(fd, 0, SEEK_SET) == -1)
1562 fdisk_fatal(unable_to_seek);
1563 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1564 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001565#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001566 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1567 fdisk_fatal(unable_to_seek);
1568 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1569 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001570#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001571 sync_disks();
1572 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001573}
1574
1575
1576#if !defined (__alpha__)
1577static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001578xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001579{
Rob Landleyb73451d2006-02-24 16:29:00 +00001580 switch (linux_type) {
1581 case 0x01: /* DOS 12-bit FAT */
1582 case 0x04: /* DOS 16-bit <32M */
1583 case 0x06: /* DOS 16-bit >=32M */
1584 case 0xe1: /* DOS access */
1585 case 0xe3: /* DOS R/O */
1586 case 0xf2: /* DOS secondary */
1587 return BSD_FS_MSDOS;
1588 case 0x07: /* OS/2 HPFS */
1589 return BSD_FS_HPFS;
1590 default:
1591 return BSD_FS_OTHER;
1592 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001593}
1594
1595static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001596xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001597{
Rob Landleyb73451d2006-02-24 16:29:00 +00001598 int k, i;
1599 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001600
Rob Landleyb73451d2006-02-24 16:29:00 +00001601 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001602
Rob Landleyb73451d2006-02-24 16:29:00 +00001603 if (!xbsd_check_new_partition(&i))
1604 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001605
Rob Landleyb73451d2006-02-24 16:29:00 +00001606 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001607
Rob Landleyb73451d2006-02-24 16:29:00 +00001608 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1609 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1610 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001611}
1612#endif
1613
1614#if defined (__alpha__)
1615
1616#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001617typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001618#endif
1619
1620static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001621alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001622{
Rob Landleyb73451d2006-02-24 16:29:00 +00001623 uint64_t *dp, sum;
1624 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001625
Rob Landleyb73451d2006-02-24 16:29:00 +00001626 dp = (uint64_t *)boot;
1627 sum = 0;
1628 for (i = 0; i < 63; i++)
1629 sum += dp[i];
1630 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001631}
1632#endif /* __alpha__ */
1633
1634#endif /* OSF_LABEL */
1635
1636#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1637static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001638__swap16(unsigned short x)
1639{
Eric Andersenacd244a2002-12-11 03:49:33 +00001640 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001641}
1642
Eric Andersenacd244a2002-12-11 03:49:33 +00001643static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001644__swap32(uint32_t x)
1645{
1646 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001647 ((x & 0xFF00) << 8) |
1648 ((x & 0xFF0000) >> 8) |
1649 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001650}
1651#endif
1652
1653#ifdef CONFIG_FEATURE_SGI_LABEL
1654/*
1655 *
1656 * fdisksgilabel.c
1657 *
1658 * Copyright (C) Andreas Neuper, Sep 1998.
1659 * This file may be modified and redistributed under
1660 * the terms of the GNU Public License.
1661 *
1662 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1663 * Internationalization
1664 */
1665
1666
Rob Landleyb73451d2006-02-24 16:29:00 +00001667static int sgi_other_endian;
1668static int debug;
1669static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001670
1671/*
1672 * only dealing with free blocks here
1673 */
1674
Rob Landleyb73451d2006-02-24 16:29:00 +00001675typedef struct {
1676 unsigned int first;
1677 unsigned int last;
1678} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001679static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1680
1681static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001682setfreelist(int i, unsigned int f, unsigned int l)
1683{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001684 freelist[i].first = f;
1685 freelist[i].last = l;
1686}
1687
1688static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001689add2freelist(unsigned int f, unsigned int l)
1690{
1691 int i;
1692 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001693 if (freelist[i].last == 0)
1694 break;
1695 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001696}
1697
1698static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001699clearfreelist(void)
1700{
Eric Andersen040f4402003-07-30 08:40:37 +00001701 int i;
1702
1703 for (i = 0; i < 17 ; i++)
1704 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001705}
1706
Eric Andersen040f4402003-07-30 08:40:37 +00001707static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001708isinfreelist(unsigned int b)
1709{
Eric Andersen040f4402003-07-30 08:40:37 +00001710 int i;
1711
1712 for (i = 0; i < 17 ; i++)
1713 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001714 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001715 return 0;
1716}
1717 /* return last vacant block of this stride (never 0). */
1718 /* the '>=' is not quite correct, but simplifies the code */
1719/*
1720 * end of free blocks section
1721 */
1722
1723static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001724/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1725/* 0x01 */ { "\x01" "SGI trkrepl" },
1726/* 0x02 */ { "\x02" "SGI secrepl" },
1727/* SGI_SWAP */ { "\x03" "SGI raw" },
1728/* 0x04 */ { "\x04" "SGI bsd" },
1729/* 0x05 */ { "\x05" "SGI sysv" },
1730/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1731/* SGI_EFS */ { "\x07" "SGI efs" },
1732/* 0x08 */ { "\x08" "SGI lvol" },
1733/* 0x09 */ { "\x09" "SGI rlvol" },
1734/* SGI_XFS */ { "\x0a" "SGI xfs" },
1735/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1736/* SGI_XLV */ { "\x0c" "SGI xlv" },
1737/* SGI_XVM */ { "\x0d" "SGI xvm" },
1738/* LINUX_SWAP */ { "\x82" "Linux swap" },
1739/* LINUX_NATIVE */ { "\x83" "Linux native" },
1740/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1741/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1742 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001743};
1744
1745
1746static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001747sgi_get_nsect(void)
1748{
1749 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001750}
1751
1752static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001753sgi_get_ntrks(void)
1754{
1755 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001756}
1757
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001758static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001759two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1760{
1761 int i = 0;
1762 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001763
Rob Landleyb73451d2006-02-24 16:29:00 +00001764 size /= sizeof(unsigned int);
1765 for (i = 0; i < size; i++)
1766 sum -= SGI_SSWAP32(base[i]);
1767 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001768}
1769
1770static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001771check_sgi_label(void)
1772{
1773 if (sizeof(sgilabel) > 512) {
1774 fprintf(stderr,
1775 _("According to MIPS Computer Systems, Inc the "
1776 "Label must not contain more than 512 bytes\n"));
1777 exit(1);
1778 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001779
Rob Landleyb73451d2006-02-24 16:29:00 +00001780 if (sgilabel->magic != SGI_LABEL_MAGIC
1781 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001782 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001783 return 0;
1784 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001785
Rob Landleyb73451d2006-02-24 16:29:00 +00001786 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1787 /*
1788 * test for correct checksum
1789 */
1790 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1791 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001792 fprintf(stderr,
1793 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001794 }
1795 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001796 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001797 partitions = 16;
1798 sgi_volumes = 15;
1799 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001800}
1801
Eric Andersen040f4402003-07-30 08:40:37 +00001802static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001803sgi_get_start_sector(int i)
1804{
1805 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001806}
1807
Eric Andersen040f4402003-07-30 08:40:37 +00001808static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001809sgi_get_num_sectors(int i)
1810{
1811 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001812}
1813
1814static int
Eric Andersen040f4402003-07-30 08:40:37 +00001815sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001816{
Rob Landleyb73451d2006-02-24 16:29:00 +00001817 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001818}
1819
1820static int
1821sgi_get_bootpartition(void)
1822{
Rob Landleyb73451d2006-02-24 16:29:00 +00001823 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001824}
1825
1826static int
1827sgi_get_swappartition(void)
1828{
Rob Landleyb73451d2006-02-24 16:29:00 +00001829 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001830}
1831
1832static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001833sgi_list_table(int xtra)
1834{
1835 int i, w, wd;
1836 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001837
Rob Landleyb73451d2006-02-24 16:29:00 +00001838 if(xtra) {
1839 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1840 "%d cylinders, %d physical cylinders\n"
1841 "%d extra sects/cyl, interleave %d:1\n"
1842 "%s\n"
1843 "Units = %s of %d * 512 bytes\n\n"),
1844 disk_device, heads, sectors, cylinders,
1845 SGI_SSWAP16(sgiparam.pcylcount),
1846 SGI_SSWAP16(sgiparam.sparecyl),
1847 SGI_SSWAP16(sgiparam.ilfact),
1848 (char *)sgilabel,
1849 str_units(PLURAL), units_per_sector);
1850 } else {
1851 printf( _("\nDisk %s (SGI disk label): "
1852 "%d heads, %d sectors, %d cylinders\n"
1853 "Units = %s of %d * 512 bytes\n\n"),
1854 disk_device, heads, sectors, cylinders,
1855 str_units(PLURAL), units_per_sector );
1856 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001857
Rob Landleyb73451d2006-02-24 16:29:00 +00001858 w = strlen(disk_device);
1859 wd = strlen(_("Device"));
1860 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001861 w = wd;
1862
Rob Landleyb73451d2006-02-24 16:29:00 +00001863 printf(_("----- partitions -----\n"
1864 "Pt# %*s Info Start End Sectors Id System\n"),
1865 w + 2, _("Device"));
1866 for (i = 0 ; i < partitions; i++) {
1867 if( sgi_get_num_sectors(i) || debug ) {
1868 uint32_t start = sgi_get_start_sector(i);
1869 uint32_t len = sgi_get_num_sectors(i);
1870 kpi++; /* only count nonempty partitions */
1871 printf(
1872 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1873/* fdisk part number */ i+1,
1874/* device */ partname(disk_device, kpi, w+3),
1875/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1876/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1877/* start */ (long) scround(start),
1878/* end */ (long) scround(start+len)-1,
1879/* no odd flag on end */(long) len,
1880/* type id */ sgi_get_sysid(i),
1881/* type name */ partition_type(sgi_get_sysid(i)));
1882 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001883 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001884 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1885 "----- Directory Entries -----\n"),
1886 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001887 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001888 if (sgilabel->directory[i].vol_file_size) {
1889 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1890 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1891 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001892
Rob Landleyb73451d2006-02-24 16:29:00 +00001893 printf(_("%2d: %-10s sector%5u size%8u\n"),
1894 i, (char*)name, (unsigned int) start, (unsigned int) len);
1895 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001896 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001897}
1898
1899static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001900sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001901{
Rob Landleyb73451d2006-02-24 16:29:00 +00001902 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001903}
1904
Eric Andersen040f4402003-07-30 08:40:37 +00001905static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001906sgi_get_lastblock(void)
1907{
1908 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001909}
1910
1911static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001912sgi_set_swappartition(int i)
1913{
1914 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001915}
1916
1917static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001918sgi_check_bootfile(const char* aFile)
1919{
1920 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1921 printf(_("\nInvalid Bootfile!\n"
1922 "\tThe bootfile must be an absolute non-zero pathname,\n"
1923 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1924 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001925 } else {
1926 if (strlen(aFile) > 16) {
1927 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001928 "16 bytes maximum.\n"));
1929 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001930 } else {
1931 if (aFile[0] != '/') {
1932 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001933 "fully qualified pathname.\n"));
1934 return 0;
1935 }
Eric Andersen040f4402003-07-30 08:40:37 +00001936 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001937 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001938 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001939 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1940 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001941 /* filename is correct and did change */
1942 return 1;
1943 }
1944 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001945}
1946
1947static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001948sgi_get_bootfile(void)
1949{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001950 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001951}
1952
1953static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001954sgi_set_bootfile(const char* aFile)
1955{
1956 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001957
Rob Landleyb73451d2006-02-24 16:29:00 +00001958 if (sgi_check_bootfile(aFile)) {
1959 while (i < 16) {
1960 if ((aFile[i] != '\n') /* in principle caught again by next line */
1961 && (strlen(aFile) > i))
1962 sgilabel->boot_file[i] = aFile[i];
1963 else
1964 sgilabel->boot_file[i] = 0;
1965 i++;
1966 }
1967 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001968 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001969}
1970
1971static void
1972create_sgiinfo(void)
1973{
Rob Landleyb73451d2006-02-24 16:29:00 +00001974 /* I keep SGI's habit to write the sgilabel to the second block */
1975 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1976 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
Rob Landley11c7a7b2006-06-25 22:39:24 +00001977 strcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001978}
1979
Eric Andersen040f4402003-07-30 08:40:37 +00001980static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001981
1982static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001983sgi_write_table(void)
1984{
1985 sgilabel->csum = 0;
1986 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1987 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1988 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00001989 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00001990
1991 if (lseek(fd, 0, SEEK_SET) < 0)
1992 fdisk_fatal(unable_to_seek);
1993 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1994 fdisk_fatal(unable_to_write);
1995 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
1996 /*
1997 * keep this habit of first writing the "sgilabel".
1998 * I never tested whether it works without (AN 981002).
1999 */
2000 sgiinfo *info = fill_sgiinfo();
2001 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2002 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2003 fdisk_fatal(unable_to_seek);
2004 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2005 fdisk_fatal(unable_to_write);
2006 free(info);
2007 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002008}
2009
2010static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002011compare_start(int *x, int *y)
2012{
2013 /*
2014 * sort according to start sectors
2015 * and prefers largest partition:
2016 * entry zero is entire disk entry
2017 */
2018 unsigned int i = *x;
2019 unsigned int j = *y;
2020 unsigned int a = sgi_get_start_sector(i);
2021 unsigned int b = sgi_get_start_sector(j);
2022 unsigned int c = sgi_get_num_sectors(i);
2023 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002024
Rob Landleyb73451d2006-02-24 16:29:00 +00002025 if (a == b)
2026 return (d > c) ? 1 : (d == c) ? 0 : -1;
2027 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002028}
2029
2030
2031static int
Eric Andersen040f4402003-07-30 08:40:37 +00002032verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002033{
Rob Landleyb73451d2006-02-24 16:29:00 +00002034 int Index[16]; /* list of valid partitions */
2035 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2036 int entire = 0, i = 0;
2037 unsigned int start = 0;
2038 long long gap = 0; /* count unused blocks */
2039 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002040
Rob Landleyb73451d2006-02-24 16:29:00 +00002041 clearfreelist();
2042 for (i = 0; i < 16; i++) {
2043 if (sgi_get_num_sectors(i) != 0) {
2044 Index[sortcount++] = i;
2045 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2046 if (entire++ == 1) {
2047 if (verbose)
2048 printf(_("More than one entire disk entry present.\n"));
2049 }
2050 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002051 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002052 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002053 if (sortcount == 0) {
2054 if (verbose)
2055 printf(_("No partitions defined\n"));
2056 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2057 }
2058 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2059 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2060 if ((Index[0] != 10) && verbose)
2061 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2062 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2063 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002064 "at block 0,\n"
2065 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002066 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002067 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002068 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2069 printf(_("The entire disk partition is only %d diskblock large,\n"
2070 "but the disk is %d diskblocks long.\n"),
2071 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002072 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002073 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002074 if (verbose)
2075 printf(_("One Partition (#11) should cover the entire disk.\n"));
2076 if (debug > 2)
2077 printf("sysid=%d\tpartition=%d\n",
2078 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002079 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002080 for (i = 1, start = 0; i < sortcount; i++) {
2081 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2082
2083 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2084 if (debug) /* I do not understand how some disks fulfil it */
2085 if (verbose)
2086 printf(_("Partition %d does not start on cylinder boundary.\n"),
2087 Index[i]+1);
2088 }
2089 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2090 if (debug) /* I do not understand how some disks fulfil it */
2091 if (verbose)
2092 printf(_("Partition %d does not end on cylinder boundary.\n"),
2093 Index[i]+1);
2094 }
2095 /* We cannot handle several "entire disk" entries. */
2096 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2097 if (start > sgi_get_start_sector(Index[i])) {
2098 if (verbose)
2099 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2100 Index[i-1]+1, Index[i]+1,
2101 start - sgi_get_start_sector(Index[i]));
2102 if (gap > 0) gap = -gap;
2103 if (gap == 0) gap = -1;
2104 }
2105 if (start < sgi_get_start_sector(Index[i])) {
2106 if (verbose)
2107 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2108 sgi_get_start_sector(Index[i]) - start,
2109 start, sgi_get_start_sector(Index[i])-1);
2110 gap += sgi_get_start_sector(Index[i]) - start;
2111 add2freelist(start, sgi_get_start_sector(Index[i]));
2112 }
2113 start = sgi_get_start_sector(Index[i])
2114 + sgi_get_num_sectors(Index[i]);
2115 if (debug > 1) {
2116 if (verbose)
2117 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2118 sgi_get_start_sector(Index[i]),
2119 sgi_get_num_sectors(Index[i]),
2120 sgi_get_sysid(Index[i]));
2121 }
2122 }
2123 if (start < lastblock) {
2124 if (verbose)
2125 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2126 lastblock - start, start, lastblock-1);
2127 gap += lastblock - start;
2128 add2freelist(start, lastblock);
2129 }
2130 /*
2131 * Done with arithmetics
2132 * Go for details now
2133 */
2134 if (verbose) {
2135 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2136 printf(_("\nThe boot partition does not exist.\n"));
2137 }
2138 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2139 printf(_("\nThe swap partition does not exist.\n"));
2140 } else {
2141 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2142 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2143 printf(_("\nThe swap partition has no swap type.\n"));
2144 }
2145 if (sgi_check_bootfile("/unix"))
2146 printf(_("\tYou have chosen an unusual boot file name.\n"));
2147 }
2148 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002149}
2150
2151static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002152sgi_gaps(void)
2153{
2154 /*
2155 * returned value is:
2156 * = 0 : disk is properly filled to the rim
2157 * < 0 : there is an overlap
2158 * > 0 : there is still some vacant space
2159 */
2160 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002161}
2162
2163static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002164sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002165{
Rob Landleyb73451d2006-02-24 16:29:00 +00002166 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2167 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2168 return;
2169 }
2170 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2171 && (sgi_get_start_sector(i) < 1) ) {
2172 read_chars(
2173 _("It is highly recommended that the partition at offset 0\n"
2174 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2175 "retrieve from its directory standalone tools like sash and fx.\n"
2176 "Only the \"SGI volume\" entire disk section may violate this.\n"
2177 "Type YES if you are sure about tagging this partition differently.\n"));
2178 if (strcmp(line_ptr, _("YES\n")))
2179 return;
2180 }
2181 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002182}
2183
2184/* returns partition index of first entry marked as entire disk */
2185static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002186sgi_entire(void)
2187{
2188 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002189
Rob Landleyb73451d2006-02-24 16:29:00 +00002190 for (i = 0; i < 16; i++)
2191 if (sgi_get_sysid(i) == SGI_VOLUME)
2192 return i;
2193 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002194}
2195
2196static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002197sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2198{
2199 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2200 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2201 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2202 set_changed(i);
2203 if (sgi_gaps() < 0) /* rebuild freelist */
2204 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002205}
2206
2207static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002208sgi_set_entire(void)
2209{
2210 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002211
Rob Landleyb73451d2006-02-24 16:29:00 +00002212 for (n = 10; n < partitions; n++) {
2213 if(!sgi_get_num_sectors(n) ) {
2214 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2215 break;
2216 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002217 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002218}
2219
2220static void
2221sgi_set_volhdr(void)
2222{
Rob Landleyb73451d2006-02-24 16:29:00 +00002223 int n;
2224
2225 for (n = 8; n < partitions; n++) {
2226 if (!sgi_get_num_sectors(n)) {
2227 /*
2228 * 5 cylinders is an arbitrary value I like
2229 * IRIX 5.3 stored files in the volume header
2230 * (like sash, symmon, fx, ide) with ca. 3200
2231 * sectors.
2232 */
2233 if (heads * sectors * 5 < sgi_get_lastblock())
2234 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2235 break;
2236 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002237 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002238}
2239
2240static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002241sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002242{
Rob Landleyb73451d2006-02-24 16:29:00 +00002243 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002244}
2245
2246static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002247sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002248{
Rob Landleyb73451d2006-02-24 16:29:00 +00002249 char mesg[256];
2250 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002251
Rob Landleyb73451d2006-02-24 16:29:00 +00002252 if (n == 10) {
2253 sys = SGI_VOLUME;
2254 } else if (n == 8) {
2255 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002256 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002257 if(sgi_get_num_sectors(n)) {
2258 printf(_("Partition %d is already defined. Delete "
2259 "it before re-adding it.\n"), n + 1);
2260 return;
2261 }
2262 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2263 printf(_("Attempting to generate entire disk entry automatically.\n"));
2264 sgi_set_entire();
2265 sgi_set_volhdr();
2266 }
2267 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2268 printf(_("The entire disk is already covered with partitions.\n"));
2269 return;
2270 }
2271 if (sgi_gaps() < 0) {
2272 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2273 return;
2274 }
2275 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2276 while (1) {
2277 if(sys == SGI_VOLUME) {
2278 last = sgi_get_lastblock();
2279 first = read_int(0, 0, last-1, 0, mesg);
2280 if (first != 0) {
2281 printf(_("It is highly recommended that eleventh partition\n"
2282 "covers the entire disk and is of type `SGI volume'\n"));
2283 }
2284 } else {
2285 first = freelist[0].first;
2286 last = freelist[0].last;
2287 first = read_int(scround(first), scround(first), scround(last)-1,
2288 0, mesg);
2289 }
2290 if (display_in_cyl_units)
2291 first *= units_per_sector;
2292 else
2293 first = first; /* align to cylinder if you know how ... */
2294 if(!last )
2295 last = isinfreelist(first);
2296 if(last == 0) {
2297 printf(_("You will get a partition overlap on the disk. "
2298 "Fix it first!\n"));
2299 } else
2300 break;
2301 }
2302 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2303 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2304 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002305 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002306 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002307 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002308 last = last; /* align to cylinder if You know how ... */
2309 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2310 printf(_("It is highly recommended that eleventh partition\n"
2311 "covers the entire disk and is of type `SGI volume'\n"));
2312 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002313}
2314
Eric Andersen040f4402003-07-30 08:40:37 +00002315#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002316static void
2317create_sgilabel(void)
2318{
Rob Landleyb73451d2006-02-24 16:29:00 +00002319 struct hd_geometry geometry;
2320 struct {
2321 unsigned int start;
2322 unsigned int nsect;
2323 int sysid;
2324 } old[4];
2325 int i = 0;
2326 long longsectors; /* the number of sectors on the device */
2327 int res; /* the result from the ioctl */
2328 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002329
Rob Landleyb73451d2006-02-24 16:29:00 +00002330 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002331
Rob Landleyb73451d2006-02-24 16:29:00 +00002332 fprintf( stderr,
2333 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2334 "until you decide to write them. After that, of course, the previous\n"
2335 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002336
Rob Landley2c39eee2006-05-05 16:54:40 +00002337 sgi_other_endian = (BB_LITTLE_ENDIAN);
Rob Landleyb73451d2006-02-24 16:29:00 +00002338 res = ioctl(fd, BLKGETSIZE, &longsectors);
2339 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2340 heads = geometry.heads;
2341 sectors = geometry.sectors;
2342 if (res == 0) {
2343 /* the get device size ioctl was successful */
2344 cylinders = longsectors / (heads * sectors);
2345 cylinders /= sec_fac;
2346 } else {
2347 /* otherwise print error and use truncated version */
2348 cylinders = geometry.cylinders;
2349 fprintf(stderr,
2350 _("Warning: BLKGETSIZE ioctl failed on %s. "
2351 "Using geometry cylinder value of %d.\n"
2352 "This value may be truncated for devices"
2353 " > 33.8 GB.\n"), disk_device, cylinders);
2354 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002355 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002356 for (i = 0; i < 4; i++) {
2357 old[i].sysid = 0;
2358 if (valid_part_table_flag(MBRbuffer)) {
2359 if(get_part_table(i)->sys_ind) {
2360 old[i].sysid = get_part_table(i)->sys_ind;
2361 old[i].start = get_start_sect(get_part_table(i));
2362 old[i].nsect = get_nr_sects(get_part_table(i));
2363 printf(_("Trying to keep parameters of partition %d.\n"), i);
2364 if (debug)
2365 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2366 old[i].sysid, old[i].start, old[i].nsect);
2367 }
2368 }
2369 }
Eric Andersen040f4402003-07-30 08:40:37 +00002370
Rob Landleyb73451d2006-02-24 16:29:00 +00002371 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2372 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2373 sgilabel->boot_part = SGI_SSWAP16(0);
2374 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002375
Rob Landleyb73451d2006-02-24 16:29:00 +00002376 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2377 memset(sgilabel->boot_file, 0, 16);
2378 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002379
Rob Landleyb73451d2006-02-24 16:29:00 +00002380 sgilabel->devparam.skew = (0);
2381 sgilabel->devparam.gap1 = (0);
2382 sgilabel->devparam.gap2 = (0);
2383 sgilabel->devparam.sparecyl = (0);
2384 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2385 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2386 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002387 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002388 sgilabel->devparam.cmd_tag_queue_depth = (0);
2389 sgilabel->devparam.unused0 = (0);
2390 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2391 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002392 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002393 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2394 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2395 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002396 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002397 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2398 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2399 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2400 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2401 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2402 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2403 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2404 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2405 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2406 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2407 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002408 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002409 partitions = 16;
2410 sgi_volumes = 15;
2411 sgi_set_entire();
2412 sgi_set_volhdr();
2413 for (i = 0; i < 4; i++) {
2414 if(old[i].sysid) {
2415 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2416 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002417 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002418}
2419
2420static void
2421sgi_set_xcyl(void)
2422{
Rob Landleyb73451d2006-02-24 16:29:00 +00002423 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002424}
Eric Andersen040f4402003-07-30 08:40:37 +00002425#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002426
2427/* _____________________________________________________________
2428 */
2429
Eric Andersen040f4402003-07-30 08:40:37 +00002430static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002431fill_sgiinfo(void)
2432{
Rob Landleyb73451d2006-02-24 16:29:00 +00002433 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002434
Rob Landleyb73451d2006-02-24 16:29:00 +00002435 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2436 info->b1 = SGI_SSWAP32(-1);
2437 info->b2 = SGI_SSWAP16(-1);
2438 info->b3 = SGI_SSWAP16(1);
2439 /* You may want to replace this string !!!!!!! */
2440 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2441 strcpy( (char*)info->serial, "0000" );
2442 info->check1816 = SGI_SSWAP16(18*256 +16 );
2443 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2444 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002445}
2446#endif /* SGI_LABEL */
2447
2448
2449#ifdef CONFIG_FEATURE_SUN_LABEL
2450/*
2451 * fdisksunlabel.c
2452 *
2453 * I think this is mostly, or entirely, due to
2454 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2455 *
2456 * Merged with fdisk for other architectures, aeb, June 1998.
2457 *
2458 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2459 * Internationalization
2460 */
2461
2462
Rob Landleyb73451d2006-02-24 16:29:00 +00002463static int sun_other_endian;
2464static int scsi_disk;
2465static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002466
2467#ifndef IDE0_MAJOR
2468#define IDE0_MAJOR 3
2469#endif
2470#ifndef IDE1_MAJOR
2471#define IDE1_MAJOR 22
2472#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002473
Rob Landleyb73451d2006-02-24 16:29:00 +00002474static void
2475guess_device_type(void)
2476{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002477 struct stat bootstat;
2478
Rob Landleyb73451d2006-02-24 16:29:00 +00002479 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002480 scsi_disk = 0;
2481 floppy = 0;
2482 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002483 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2484 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002485 scsi_disk = 0;
2486 floppy = 0;
2487 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002488 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002489 scsi_disk = 0;
2490 floppy = 1;
2491 } else {
2492 scsi_disk = 1;
2493 floppy = 0;
2494 }
2495}
2496
2497static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002498 { "\x00" "Empty" }, /* 0 */
2499 { "\x01" "Boot" }, /* 1 */
2500 { "\x02" "SunOS root" }, /* 2 */
2501 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2502 { "\x04" "SunOS usr" }, /* 4 */
2503 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2504 { "\x06" "SunOS stand" }, /* 6 */
2505 { "\x07" "SunOS var" }, /* 7 */
2506 { "\x08" "SunOS home" }, /* 8 */
2507 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2508 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2509 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002510/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002511 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2512 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002513};
2514
2515
2516static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002517set_sun_partition(int i, uint start, uint stop, int sysid)
2518{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002519 sunlabel->infos[i].id = sysid;
2520 sunlabel->partitions[i].start_cylinder =
2521 SUN_SSWAP32(start / (heads * sectors));
2522 sunlabel->partitions[i].num_sectors =
2523 SUN_SSWAP32(stop - start);
2524 set_changed(i);
2525}
2526
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002527static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002528check_sun_label(void)
2529{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002530 unsigned short *ush;
2531 int csum;
2532
Rob Landleyb73451d2006-02-24 16:29:00 +00002533 if (sunlabel->magic != SUN_LABEL_MAGIC
2534 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002535 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002536 sun_other_endian = 0;
2537 return 0;
2538 }
2539 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2540 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2541 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2542 if (csum) {
2543 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2544 "Probably you'll have to set all the values,\n"
2545 "e.g. heads, sectors, cylinders and partitions\n"
2546 "or force a fresh label (s command in main menu)\n"));
2547 } else {
2548 heads = SUN_SSWAP16(sunlabel->ntrks);
2549 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2550 sectors = SUN_SSWAP16(sunlabel->nsect);
2551 }
2552 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002553 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002554 partitions = 8;
2555 return 1;
2556}
2557
2558static const struct sun_predefined_drives {
2559 const char *vendor;
2560 const char *model;
2561 unsigned short sparecyl;
2562 unsigned short ncyl;
2563 unsigned short nacyl;
2564 unsigned short pcylcount;
2565 unsigned short ntrks;
2566 unsigned short nsect;
2567 unsigned short rspeed;
2568} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002569 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2570 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2571 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2572 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2573 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2574 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2575 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2576 { "","SUN0104",1,974,2,1019,6,35,3662},
2577 { "","SUN0207",4,1254,2,1272,9,36,3600},
2578 { "","SUN0327",3,1545,2,1549,9,46,3600},
2579 { "","SUN0340",0,1538,2,1544,6,72,4200},
2580 { "","SUN0424",2,1151,2,2500,9,80,4400},
2581 { "","SUN0535",0,1866,2,2500,7,80,5400},
2582 { "","SUN0669",5,1614,2,1632,15,54,3600},
2583 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2584 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2585 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2586 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2587 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002588};
2589
2590static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002591sun_autoconfigure_scsi(void)
2592{
2593 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002594
2595#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002596 unsigned int id[2];
2597 char buffer[2048];
2598 char buffer2[2048];
2599 FILE *pfd;
2600 char *vendor;
2601 char *model;
2602 char *q;
2603 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002604
Rob Landleyb73451d2006-02-24 16:29:00 +00002605 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2606 sprintf(buffer,
2607 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002608#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002609 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002610#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002611 /* This is very wrong (works only if you have one HBA),
2612 but I haven't found a way how to get hostno
2613 from the current kernel */
2614 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002615#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002616 (id[0]>>16) & 0xff,
2617 id[0] & 0xff,
2618 (id[0]>>8) & 0xff
2619 );
2620 pfd = fopen("/proc/scsi/scsi","r");
2621 if (pfd) {
2622 while (fgets(buffer2, 2048, pfd)) {
2623 if (!strcmp(buffer, buffer2)) {
2624 if (fgets(buffer2,2048,pfd)) {
2625 q = strstr(buffer2,"Vendor: ");
2626 if (q) {
2627 q += 8;
2628 vendor = q;
2629 q = strstr(q," ");
2630 *q++ = 0; /* truncate vendor name */
2631 q = strstr(q,"Model: ");
2632 if (q) {
2633 *q = 0;
2634 q += 7;
2635 model = q;
2636 q = strstr(q," Rev: ");
2637 if (q) {
2638 *q = 0;
2639 for (i = 0; i < SIZE(sun_drives); i++) {
2640 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2641 continue;
2642 if (!strstr(model, sun_drives[i].model))
2643 continue;
2644 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2645 p = sun_drives + i;
2646 break;
2647 }
2648 }
2649 }
2650 }
2651 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002652 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002653 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002654 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002655 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002656 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002657 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002658#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002659 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002660}
2661
Rob Landleyb73451d2006-02-24 16:29:00 +00002662static void
2663create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002664{
2665 struct hd_geometry geometry;
2666 unsigned int ndiv;
2667 int i;
2668 unsigned char c;
2669 const struct sun_predefined_drives *p = NULL;
2670
2671 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002672 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2673 "until you decide to write them. After that, of course, the previous\n"
2674 "content won't be recoverable.\n\n"));
Rob Landley2c39eee2006-05-05 16:54:40 +00002675 sun_other_endian = BB_LITTLE_ENDIAN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002676 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2677 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2678 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002679 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002680 " ? auto configure\n"
2681 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002682 for (i = 0; i < SIZE(sun_drives); i++) {
2683 printf(" %c %s%s%s\n",
2684 i + 'a', sun_drives[i].vendor,
2685 (*sun_drives[i].vendor) ? " " : "",
2686 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002687 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002688 while (1) {
2689 c = read_char(_("Select type (? for auto, 0 for custom): "));
2690 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2691 p = sun_drives + c - 'a';
2692 break;
2693 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2694 p = sun_drives + c - 'A';
2695 break;
2696 } else if (c == '0') {
2697 break;
2698 } else if (c == '?' && scsi_disk) {
2699 p = sun_autoconfigure_scsi();
2700 if (!p)
2701 printf(_("Autoconfigure failed.\n"));
2702 else
2703 break;
2704 }
2705 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002706 }
2707 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002708 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2709 heads = geometry.heads;
2710 sectors = geometry.sectors;
2711 cylinders = geometry.cylinders;
2712 } else {
2713 heads = 0;
2714 sectors = 0;
2715 cylinders = 0;
2716 }
2717 if (floppy) {
2718 sunlabel->nacyl = 0;
2719 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2720 sunlabel->rspeed = SUN_SSWAP16(300);
2721 sunlabel->ilfact = SUN_SSWAP16(1);
2722 sunlabel->sparecyl = 0;
2723 } else {
2724 heads = read_int(1,heads,1024,0,_("Heads"));
2725 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002726 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002727 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002728 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002729 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2730 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2731 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2732 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2733 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2734 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2735 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002736 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002737 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2738 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2739 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2740 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2741 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2742 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2743 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2744 sunlabel->ilfact = SUN_SSWAP16(1);
2745 cylinders = p->ncyl;
2746 heads = p->ntrks;
2747 sectors = p->nsect;
2748 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002749 }
2750
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002751 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002752 "%s%s%s cyl %d alt %d hd %d sec %d",
2753 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2754 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002755 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2756
2757 sunlabel->ntrks = SUN_SSWAP16(heads);
2758 sunlabel->nsect = SUN_SSWAP16(sectors);
2759 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2760 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002761 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002762 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002763 if (cylinders * heads * sectors >= 150 * 2048) {
2764 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2765 } else
2766 ndiv = cylinders * 2 / 3;
2767 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2768 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2769 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002770 }
2771 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2772 {
2773 unsigned short *ush = (unsigned short *)sunlabel;
2774 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002775 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002776 csum ^= *ush++;
2777 sunlabel->csum = csum;
2778 }
2779
2780 set_all_unchanged();
2781 set_changed(0);
2782 get_boot(create_empty_sun);
2783}
2784
2785static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002786toggle_sunflags(int i, unsigned char mask)
2787{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002788 if (sunlabel->infos[i].flags & mask)
2789 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002790 else
2791 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002792 set_changed(i);
2793}
2794
2795static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002796fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2797{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002798 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002799
2800 *start = 0;
2801 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002802 for (i = 0; i < partitions; i++) {
2803 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002804 && sunlabel->infos[i].id
2805 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002806 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2807 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2808 if (continuous) {
2809 if (starts[i] == *start)
2810 *start += lens[i];
2811 else if (starts[i] + lens[i] >= *stop)
2812 *stop = starts[i];
2813 else
2814 continuous = 0;
2815 /* There will be probably more gaps
2816 than one, so lets check afterwards */
2817 }
2818 } else {
2819 starts[i] = 0;
2820 lens[i] = 0;
2821 }
2822 }
2823}
2824
2825static uint *verify_sun_starts;
2826
2827static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002828verify_sun_cmp(int *a, int *b)
2829{
2830 if (*a == -1) return 1;
2831 if (*b == -1) return -1;
2832 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2833 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002834}
2835
2836static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002837verify_sun(void)
2838{
2839 uint starts[8], lens[8], start, stop;
2840 int i,j,k,starto,endo;
2841 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002842
Rob Landleyb73451d2006-02-24 16:29:00 +00002843 verify_sun_starts = starts;
2844 fetch_sun(starts,lens,&start,&stop);
2845 for (k = 0; k < 7; k++) {
2846 for (i = 0; i < 8; i++) {
2847 if (k && (lens[i] % (heads * sectors))) {
2848 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002849 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002850 if (lens[i]) {
2851 for (j = 0; j < i; j++)
2852 if (lens[j]) {
2853 if (starts[j] == starts[i]+lens[i]) {
2854 starts[j] = starts[i]; lens[j] += lens[i];
2855 lens[i] = 0;
2856 } else if (starts[i] == starts[j]+lens[j]){
2857 lens[j] += lens[i];
2858 lens[i] = 0;
2859 } else if (!k) {
2860 if (starts[i] < starts[j]+lens[j]
2861 && starts[j] < starts[i]+lens[i]) {
2862 starto = starts[i];
2863 if (starts[j] > starto)
2864 starto = starts[j];
2865 endo = starts[i]+lens[i];
2866 if (starts[j]+lens[j] < endo)
2867 endo = starts[j]+lens[j];
2868 printf(_("Partition %d overlaps with others in "
2869 "sectors %d-%d\n"), i+1, starto, endo);
2870 }
2871 }
2872 }
2873 }
2874 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002875 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002876 for (i = 0; i < 8; i++) {
2877 if (lens[i])
2878 array[i] = i;
2879 else
2880 array[i] = -1;
2881 }
2882 qsort(array,SIZE(array),sizeof(array[0]),
2883 (int (*)(const void *,const void *)) verify_sun_cmp);
2884 if (array[0] == -1) {
2885 printf(_("No partitions defined\n"));
2886 return;
2887 }
2888 stop = cylinders * heads * sectors;
2889 if (starts[array[0]])
2890 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2891 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2892 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2893 }
2894 start = starts[array[i]] + lens[array[i]];
2895 if (start < stop)
2896 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002897}
2898
2899static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002900add_sun_partition(int n, int sys)
2901{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002902 uint start, stop, stop2;
2903 uint starts[8], lens[8];
2904 int whole_disk = 0;
2905
2906 char mesg[256];
2907 int i, first, last;
2908
2909 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2910 printf(_("Partition %d is already defined. Delete "
2911 "it before re-adding it.\n"), n + 1);
2912 return;
2913 }
2914
2915 fetch_sun(starts,lens,&start,&stop);
2916 if (stop <= start) {
2917 if (n == 2)
2918 whole_disk = 1;
2919 else {
2920 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002921 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002922 return;
2923 }
2924 }
2925 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002926 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002927 if (whole_disk)
2928 first = read_int(0, 0, 0, 0, mesg);
2929 else
2930 first = read_int(scround(start), scround(stop)+1,
2931 scround(stop), 0, mesg);
2932 if (display_in_cyl_units)
2933 first *= units_per_sector;
2934 else
2935 /* Starting sector has to be properly aligned */
2936 first = (first + heads * sectors - 1) / (heads * sectors);
2937 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002938 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002939It is highly recommended that the third partition covers the whole disk\n\
2940and is of type `Whole disk'\n");
2941 /* ewt asks to add: "don't start a partition at cyl 0"
2942 However, edmundo@rano.demon.co.uk writes:
2943 "In addition to having a Sun partition table, to be able to
2944 boot from the disc, the first partition, /dev/sdX1, must
2945 start at cylinder 0. This means that /dev/sdX1 contains
2946 the partition table and the boot block, as these are the
2947 first two sectors of the disc. Therefore you must be
2948 careful what you use /dev/sdX1 for. In particular, you must
2949 not use a partition starting at cylinder 0 for Linux swap,
2950 as that would overwrite the partition table and the boot
2951 block. You may, however, use such a partition for a UFS
2952 or EXT2 file system, as these file systems leave the first
2953 1024 bytes undisturbed. */
2954 /* On the other hand, one should not use partitions
2955 starting at block 0 in an md, or the label will
2956 be trashed. */
2957 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002958 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002959 break;
2960 if (i < partitions && !whole_disk) {
2961 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002962 whole_disk = 1;
2963 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002964 }
2965 printf(_("Sector %d is already allocated\n"), first);
2966 } else
2967 break;
2968 }
2969 stop = cylinders * heads * sectors;
2970 stop2 = stop;
2971 for (i = 0; i < partitions; i++) {
2972 if (starts[i] > first && starts[i] < stop)
2973 stop = starts[i];
2974 }
2975 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002976 _("Last %s or +size or +sizeM or +sizeK"),
2977 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002978 if (whole_disk)
2979 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2980 0, mesg);
2981 else if (n == 2 && !first)
2982 last = read_int(scround(first), scround(stop2), scround(stop2),
2983 scround(first), mesg);
2984 else
2985 last = read_int(scround(first), scround(stop), scround(stop),
2986 scround(first), mesg);
2987 if (display_in_cyl_units)
2988 last *= units_per_sector;
2989 if (n == 2 && !first) {
2990 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002991 whole_disk = 1;
2992 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002993 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002994 printf(_("You haven't covered the whole disk with "
2995 "the 3rd partition, but your value\n"
2996 "%d %s covers some other partition. "
2997 "Your entry has been changed\n"
2998 "to %d %s\n"),
2999 scround(last), str_units(SINGULAR),
3000 scround(stop), str_units(SINGULAR));
3001 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003002 }
3003 } else if (!whole_disk && last > stop)
3004 last = stop;
3005
Rob Landleyb73451d2006-02-24 16:29:00 +00003006 if (whole_disk)
3007 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003008 set_sun_partition(n, first, last, sys);
3009}
3010
3011static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003012sun_delete_partition(int i)
3013{
Eric Andersen040f4402003-07-30 08:40:37 +00003014 unsigned int nsec;
3015
Rob Landleyb73451d2006-02-24 16:29:00 +00003016 if (i == 2
3017 && sunlabel->infos[i].id == WHOLE_DISK
3018 && !sunlabel->partitions[i].start_cylinder
3019 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003020 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003021 "consider leaving this\n"
3022 "partition as Whole disk (5), starting at 0, with %u "
3023 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003024 sunlabel->infos[i].id = 0;
3025 sunlabel->partitions[i].num_sectors = 0;
3026}
3027
3028static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003029sun_change_sysid(int i, int sys)
3030{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003031 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003032 read_chars(
3033 _("It is highly recommended that the partition at offset 0\n"
3034 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3035 "there may destroy your partition table and bootblock.\n"
3036 "Type YES if you're very sure you would like that partition\n"
3037 "tagged with 82 (Linux swap): "));
3038 if (strcmp (line_ptr, _("YES\n")))
3039 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003040 }
3041 switch (sys) {
3042 case SUNOS_SWAP:
3043 case LINUX_SWAP:
3044 /* swaps are not mountable by default */
3045 sunlabel->infos[i].flags |= 0x01;
3046 break;
3047 default:
3048 /* assume other types are mountable;
3049 user can change it anyway */
3050 sunlabel->infos[i].flags &= ~0x01;
3051 break;
3052 }
3053 sunlabel->infos[i].id = sys;
3054}
3055
3056static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003057sun_list_table(int xtra)
3058{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003059 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003060
3061 w = strlen(disk_device);
3062 if (xtra)
3063 printf(
3064 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3065 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3066 "%d extra sects/cyl, interleave %d:1\n"
3067 "%s\n"
3068 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003069 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3070 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3071 SUN_SSWAP16(sunlabel->pcylcount),
3072 SUN_SSWAP16(sunlabel->sparecyl),
3073 SUN_SSWAP16(sunlabel->ilfact),
3074 (char *)sunlabel,
3075 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003076 else
3077 printf(
3078 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3079 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003080 disk_device, heads, sectors, cylinders,
3081 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003082
3083 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003084 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003085 for (i = 0 ; i < partitions; i++) {
3086 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003087 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3088 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003089 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3090 partname(disk_device, i+1, w), /* device */
3091 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3092 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3093 (long) scround(start), /* start */
3094 (long) scround(start+len), /* end */
3095 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3096 sunlabel->infos[i].id, /* type id */
3097 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003098 }
3099 }
3100}
3101
Eric Andersen040f4402003-07-30 08:40:37 +00003102#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3103
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003104static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003105sun_set_alt_cyl(void)
3106{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003107 sunlabel->nacyl =
3108 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003109 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003110}
3111
3112static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003113sun_set_ncyl(int cyl)
3114{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003115 sunlabel->ncyl = SUN_SSWAP16(cyl);
3116}
3117
3118static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003119sun_set_xcyl(void)
3120{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003121 sunlabel->sparecyl =
3122 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003123 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003124}
3125
3126static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003127sun_set_ilfact(void)
3128{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003129 sunlabel->ilfact =
3130 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003131 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003132}
3133
3134static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003135sun_set_rspeed(void)
3136{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003137 sunlabel->rspeed =
3138 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003139 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003140}
3141
3142static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003143sun_set_pcylcount(void)
3144{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003145 sunlabel->pcylcount =
3146 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003147 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003148}
Eric Andersen040f4402003-07-30 08:40:37 +00003149#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003150
3151static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003152sun_write_table(void)
3153{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003154 unsigned short *ush = (unsigned short *)sunlabel;
3155 unsigned short csum = 0;
3156
Rob Landleyb73451d2006-02-24 16:29:00 +00003157 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003158 csum ^= *ush++;
3159 sunlabel->csum = csum;
3160 if (lseek(fd, 0, SEEK_SET) < 0)
3161 fdisk_fatal(unable_to_seek);
3162 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3163 fdisk_fatal(unable_to_write);
3164}
3165#endif /* SUN_LABEL */
3166
3167/* DOS partition types */
3168
3169static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003170 { "\x00" "Empty" },
3171 { "\x01" "FAT12" },
3172 { "\x04" "FAT16 <32M" },
3173 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3174 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3175 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3176 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3177 { "\x0b" "Win95 FAT32" },
3178 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3179 { "\x0e" "Win95 FAT16 (LBA)" },
3180 { "\x0f" "Win95 Ext'd (LBA)" },
3181 { "\x11" "Hidden FAT12" },
3182 { "\x12" "Compaq diagnostics" },
3183 { "\x14" "Hidden FAT16 <32M" },
3184 { "\x16" "Hidden FAT16" },
3185 { "\x17" "Hidden HPFS/NTFS" },
3186 { "\x1b" "Hidden Win95 FAT32" },
3187 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3188 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3189 { "\x3c" "PartitionMagic recovery" },
3190 { "\x41" "PPC PReP Boot" },
3191 { "\x42" "SFS" },
3192 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3193 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3194 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3195 { "\x82" "Linux swap" }, /* also Solaris */
3196 { "\x83" "Linux" },
3197 { "\x84" "OS/2 hidden C: drive" },
3198 { "\x85" "Linux extended" },
3199 { "\x86" "NTFS volume set" },
3200 { "\x87" "NTFS volume set" },
3201 { "\x8e" "Linux LVM" },
3202 { "\x9f" "BSD/OS" }, /* BSDI */
3203 { "\xa0" "IBM Thinkpad hibernation" },
3204 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3205 { "\xa6" "OpenBSD" },
3206 { "\xa8" "Darwin UFS" },
3207 { "\xa9" "NetBSD" },
3208 { "\xab" "Darwin boot" },
3209 { "\xb7" "BSDI fs" },
3210 { "\xb8" "BSDI swap" },
3211 { "\xbe" "Solaris boot" },
3212 { "\xeb" "BeOS fs" },
3213 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3214 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3215 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3216 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3217 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3218 autodetect using persistent
3219 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003220#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003221 { "\x02" "XENIX root" },
3222 { "\x03" "XENIX usr" },
3223 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3224 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3225 { "\x10" "OPUS" },
3226 { "\x18" "AST SmartSleep" },
3227 { "\x24" "NEC DOS" },
3228 { "\x39" "Plan 9" },
3229 { "\x40" "Venix 80286" },
3230 { "\x4d" "QNX4.x" },
3231 { "\x4e" "QNX4.x 2nd part" },
3232 { "\x4f" "QNX4.x 3rd part" },
3233 { "\x50" "OnTrack DM" },
3234 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3235 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3236 { "\x53" "OnTrack DM6 Aux3" },
3237 { "\x54" "OnTrackDM6" },
3238 { "\x55" "EZ-Drive" },
3239 { "\x56" "Golden Bow" },
3240 { "\x5c" "Priam Edisk" },
3241 { "\x61" "SpeedStor" },
3242 { "\x64" "Novell Netware 286" },
3243 { "\x65" "Novell Netware 386" },
3244 { "\x70" "DiskSecure Multi-Boot" },
3245 { "\x75" "PC/IX" },
3246 { "\x93" "Amoeba" },
3247 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3248 { "\xa7" "NeXTSTEP" },
3249 { "\xbb" "Boot Wizard hidden" },
3250 { "\xc1" "DRDOS/sec (FAT-12)" },
3251 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3252 { "\xc6" "DRDOS/sec (FAT-16)" },
3253 { "\xc7" "Syrinx" },
3254 { "\xda" "Non-FS data" },
3255 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003256 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003257 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3258 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3259 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003260 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003261 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3262 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003263 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003264 { "\xf1" "SpeedStor" },
3265 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3266 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3267 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003268#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003269 { 0 }
3270};
3271
3272
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003273
3274/* A valid partition table sector ends in 0x55 0xaa */
3275static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003276part_table_flag(const char *b)
3277{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003278 return ((uint) b[510]) + (((uint) b[511]) << 8);
3279}
3280
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003281
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003282#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003283static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003284write_part_table_flag(char *b)
3285{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003286 b[510] = 0x55;
3287 b[511] = 0xaa;
3288}
3289
3290/* start_sect and nr_sects are stored little endian on all machines */
3291/* moreover, they are not aligned correctly */
3292static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003293store4_little_endian(unsigned char *cp, unsigned int val)
3294{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003295 cp[0] = (val & 0xff);
3296 cp[1] = ((val >> 8) & 0xff);
3297 cp[2] = ((val >> 16) & 0xff);
3298 cp[3] = ((val >> 24) & 0xff);
3299}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003300#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003301
3302static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003303read4_little_endian(const unsigned char *cp)
3304{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003305 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3306 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3307}
3308
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003309#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003310static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003311set_start_sect(struct partition *p, unsigned int start_sect)
3312{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003313 store4_little_endian(p->start4, start_sect);
3314}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003315#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003316
Eric Andersend9261492004-06-28 23:50:31 +00003317static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003318get_start_sect(const struct partition *p)
3319{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003320 return read4_little_endian(p->start4);
3321}
3322
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003323#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003324static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003325set_nr_sects(struct partition *p, int32_t nr_sects)
3326{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003327 store4_little_endian(p->size4, nr_sects);
3328}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003329#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003330
Eric Andersend9261492004-06-28 23:50:31 +00003331static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003332get_nr_sects(const struct partition *p)
3333{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003334 return read4_little_endian(p->size4);
3335}
3336
3337/* normally O_RDWR, -l option gives O_RDONLY */
3338static int type_open = O_RDWR;
3339
3340
Rob Landleyb73451d2006-02-24 16:29:00 +00003341static int ext_index; /* the prime extended partition */
3342static int listing; /* no aborts for fdisk -l */
3343static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003344#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3345static int dos_changed;
3346static int nowarn; /* no warnings for fdisk -l/-s */
3347#endif
3348
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003349
3350
Rob Landleyb73451d2006-02-24 16:29:00 +00003351static uint user_cylinders, user_heads, user_sectors;
3352static uint pt_heads, pt_sectors;
3353static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003354
Eric Andersend9261492004-06-28 23:50:31 +00003355static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003356
Eric Andersen040f4402003-07-30 08:40:37 +00003357static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003358
3359
3360static jmp_buf listingbuf;
3361
Rob Landleyb73451d2006-02-24 16:29:00 +00003362static void fdisk_fatal(enum failure why)
3363{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003364 const char *message;
3365
3366 if (listing) {
3367 close(fd);
3368 longjmp(listingbuf, 1);
3369 }
3370
3371 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003372 case unable_to_open:
3373 message = "Unable to open %s\n";
3374 break;
3375 case unable_to_read:
3376 message = "Unable to read %s\n";
3377 break;
3378 case unable_to_seek:
3379 message = "Unable to seek on %s\n";
3380 break;
3381 case unable_to_write:
3382 message = "Unable to write %s\n";
3383 break;
3384 case ioctl_error:
3385 message = "BLKGETSIZE ioctl failed on %s\n";
3386 break;
3387 default:
3388 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003389 }
3390
3391 fputc('\n', stderr);
3392 fprintf(stderr, message, disk_device);
3393 exit(1);
3394}
3395
3396static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003397seek_sector(off_t secno)
3398{
Eric Andersen0a92f352004-03-30 09:21:54 +00003399 off_t offset = secno * sector_size;
3400 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003401 fdisk_fatal(unable_to_seek);
3402}
3403
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003404#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003405static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003406write_sector(off_t secno, char *buf)
3407{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003408 seek_sector(secno);
3409 if (write(fd, buf, sector_size) != sector_size)
3410 fdisk_fatal(unable_to_write);
3411}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003412#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003413
3414/* Allocate a buffer and read a partition table sector */
3415static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003416read_pte(struct pte *pe, off_t offset)
3417{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003418 pe->offset = offset;
3419 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003420 seek_sector(offset);
3421 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3422 fdisk_fatal(unable_to_read);
3423#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003424 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003425#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003426 pe->part_table = pe->ext_pointer = NULL;
3427}
3428
3429static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003430get_partition_start(const struct pte *pe)
3431{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003432 return pe->offset + get_start_sect(pe->part_table);
3433}
3434
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003435#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003436/*
3437 * Avoid warning about DOS partitions when no DOS partition was changed.
3438 * Here a heuristic "is probably dos partition".
3439 * We might also do the opposite and warn in all cases except
3440 * for "is probably nondos partition".
3441 */
3442static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003443is_dos_partition(int t)
3444{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003445 return (t == 1 || t == 4 || t == 6 ||
3446 t == 0x0b || t == 0x0c || t == 0x0e ||
3447 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3448 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3449 t == 0xc1 || t == 0xc4 || t == 0xc6);
3450}
3451
3452static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003453menu(void)
3454{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003455#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003456 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003457 puts(_("Command action"));
3458 puts(_("\ta\ttoggle a read only flag")); /* sun */
3459 puts(_("\tb\tedit bsd disklabel"));
3460 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3461 puts(_("\td\tdelete a partition"));
3462 puts(_("\tl\tlist known partition types"));
3463 puts(_("\tm\tprint this menu"));
3464 puts(_("\tn\tadd a new partition"));
3465 puts(_("\to\tcreate a new empty DOS partition table"));
3466 puts(_("\tp\tprint the partition table"));
3467 puts(_("\tq\tquit without saving changes"));
3468 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3469 puts(_("\tt\tchange a partition's system id"));
3470 puts(_("\tu\tchange display/entry units"));
3471 puts(_("\tv\tverify the partition table"));
3472 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003473#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003474 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003475#endif
3476 } else
3477#endif
3478#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003479 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003480 puts(_("Command action"));
3481 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3482 puts(_("\tb\tedit bootfile entry")); /* sgi */
3483 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3484 puts(_("\td\tdelete a partition"));
3485 puts(_("\tl\tlist known partition types"));
3486 puts(_("\tm\tprint this menu"));
3487 puts(_("\tn\tadd a new partition"));
3488 puts(_("\to\tcreate a new empty DOS partition table"));
3489 puts(_("\tp\tprint the partition table"));
3490 puts(_("\tq\tquit without saving changes"));
3491 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3492 puts(_("\tt\tchange a partition's system id"));
3493 puts(_("\tu\tchange display/entry units"));
3494 puts(_("\tv\tverify the partition table"));
3495 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003496 } else
3497#endif
3498#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003499 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003500 puts(_("Command action"));
3501 puts(_("\tm\tprint this menu"));
3502 puts(_("\to\tcreate a new empty DOS partition table"));
3503 puts(_("\tq\tquit without saving changes"));
3504 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003505 } else
3506#endif
3507 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003508 puts(_("Command action"));
3509 puts(_("\ta\ttoggle a bootable flag"));
3510 puts(_("\tb\tedit bsd disklabel"));
3511 puts(_("\tc\ttoggle the dos compatibility flag"));
3512 puts(_("\td\tdelete a partition"));
3513 puts(_("\tl\tlist known partition types"));
3514 puts(_("\tm\tprint this menu"));
3515 puts(_("\tn\tadd a new partition"));
3516 puts(_("\to\tcreate a new empty DOS partition table"));
3517 puts(_("\tp\tprint the partition table"));
3518 puts(_("\tq\tquit without saving changes"));
3519 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3520 puts(_("\tt\tchange a partition's system id"));
3521 puts(_("\tu\tchange display/entry units"));
3522 puts(_("\tv\tverify the partition table"));
3523 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003524#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003525 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003526#endif
3527 }
3528}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003529#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3530
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003531
3532#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3533static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003534xmenu(void)
3535{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003536#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003537 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003538 puts(_("Command action"));
3539 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3540 puts(_("\tc\tchange number of cylinders"));
3541 puts(_("\td\tprint the raw data in the partition table"));
3542 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3543 puts(_("\th\tchange number of heads"));
3544 puts(_("\ti\tchange interleave factor")); /*sun*/
3545 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3546 puts(_("\tm\tprint this menu"));
3547 puts(_("\tp\tprint the partition table"));
3548 puts(_("\tq\tquit without saving changes"));
3549 puts(_("\tr\treturn to main menu"));
3550 puts(_("\ts\tchange number of sectors/track"));
3551 puts(_("\tv\tverify the partition table"));
3552 puts(_("\tw\twrite table to disk and exit"));
3553 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003554 } else
3555#endif
3556#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003557 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003558 puts(_("Command action"));
3559 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3560 puts(_("\tc\tchange number of cylinders"));
3561 puts(_("\td\tprint the raw data in the partition table"));
3562 puts(_("\te\tlist extended partitions")); /* !sun */
3563 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3564 puts(_("\th\tchange number of heads"));
3565 puts(_("\tm\tprint this menu"));
3566 puts(_("\tp\tprint the partition table"));
3567 puts(_("\tq\tquit without saving changes"));
3568 puts(_("\tr\treturn to main menu"));
3569 puts(_("\ts\tchange number of sectors/track"));
3570 puts(_("\tv\tverify the partition table"));
3571 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003572 } else
3573#endif
3574#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003575 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003576 puts(_("Command action"));
3577 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3578 puts(_("\tc\tchange number of cylinders"));
3579 puts(_("\td\tprint the raw data in the partition table"));
3580 puts(_("\te\tlist extended partitions")); /* !sun */
3581 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3582 puts(_("\th\tchange number of heads"));
3583 puts(_("\tm\tprint this menu"));
3584 puts(_("\tp\tprint the partition table"));
3585 puts(_("\tq\tquit without saving changes"));
3586 puts(_("\tr\treturn to main menu"));
3587 puts(_("\ts\tchange number of sectors/track"));
3588 puts(_("\tv\tverify the partition table"));
3589 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003590 } else
3591#endif
3592 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003593 puts(_("Command action"));
3594 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3595 puts(_("\tc\tchange number of cylinders"));
3596 puts(_("\td\tprint the raw data in the partition table"));
3597 puts(_("\te\tlist extended partitions")); /* !sun */
3598 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003599#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003600 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003601#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003602 puts(_("\th\tchange number of heads"));
3603 puts(_("\tm\tprint this menu"));
3604 puts(_("\tp\tprint the partition table"));
3605 puts(_("\tq\tquit without saving changes"));
3606 puts(_("\tr\treturn to main menu"));
3607 puts(_("\ts\tchange number of sectors/track"));
3608 puts(_("\tv\tverify the partition table"));
3609 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003610 }
3611}
3612#endif /* ADVANCED mode */
3613
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003614#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003615static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003616get_sys_types(void)
3617{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003618 return (
3619#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003620 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003621#endif
3622#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003623 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003624#endif
3625 i386_sys_types);
3626}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003627#else
3628#define get_sys_types() i386_sys_types
3629#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003630
3631static const char *partition_type(unsigned char type)
3632{
3633 int i;
3634 const struct systypes *types = get_sys_types();
3635
Rob Landleyb73451d2006-02-24 16:29:00 +00003636 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003637 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003638 return types[i].name + 1;
3639
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003640 return _("Unknown");
3641}
3642
3643
3644#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3645static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003646get_sysid(int i)
3647{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003648 return (
3649#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003650 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003651#endif
3652#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003653 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003654#endif
3655 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003656}
3657
3658void list_types(const struct systypes *sys)
3659{
3660 uint last[4], done = 0, next = 0, size;
3661 int i;
3662
3663 for (i = 0; sys[i].name; i++);
3664 size = i;
3665
3666 for (i = 3; i >= 0; i--)
3667 last[3 - i] = done += (size + i - done) / (i + 1);
3668 i = done = 0;
3669
3670 do {
3671 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003672 (unsigned char)sys[next].name[0],
3673 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003674 next = last[i++] + done;
3675 if (i > 3 || next >= last[i]) {
3676 i = 0;
3677 next = ++done;
3678 }
3679 } while (done < last[0]);
3680 putchar('\n');
3681}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003682#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003683
3684static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003685is_cleared_partition(const struct partition *p)
3686{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003687 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3688 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3689 get_start_sect(p) || get_nr_sects(p));
3690}
3691
3692static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003693clear_partition(struct partition *p)
3694{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003695 if (!p)
3696 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003697 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003698}
3699
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003700#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003701static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003702set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3703{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003704 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003705 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003706
3707 if (doext) {
3708 p = ptes[i].ext_pointer;
3709 offset = extended_offset;
3710 } else {
3711 p = ptes[i].part_table;
3712 offset = ptes[i].offset;
3713 }
3714 p->boot_ind = 0;
3715 p->sys_ind = sysid;
3716 set_start_sect(p, start - offset);
3717 set_nr_sects(p, stop - start + 1);
3718 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3719 start = heads*sectors*1024 - 1;
3720 set_hsc(p->head, p->sector, p->cyl, start);
3721 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3722 stop = heads*sectors*1024 - 1;
3723 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3724 ptes[i].changed = 1;
3725}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003726#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003727
3728static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003729test_c(const char **m, const char *mesg)
3730{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003731 int val = 0;
3732 if (!*m)
3733 fprintf(stderr, _("You must set"));
3734 else {
3735 fprintf(stderr, " %s", *m);
3736 val = 1;
3737 }
3738 *m = mesg;
3739 return val;
3740}
3741
3742static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003743warn_geometry(void)
3744{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003745 const char *m = NULL;
3746 int prev = 0;
3747
3748 if (!heads)
3749 prev = test_c(&m, _("heads"));
3750 if (!sectors)
3751 prev = test_c(&m, _("sectors"));
3752 if (!cylinders)
3753 prev = test_c(&m, _("cylinders"));
3754 if (!m)
3755 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003756
3757 fprintf(stderr, "%s%s.\n"
3758#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3759 "You can do this from the extra functions menu.\n"
3760#endif
3761 , prev ? _(" and ") : " ", m);
3762
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003763 return 1;
3764}
3765
3766static void update_units(void)
3767{
3768 int cyl_units = heads * sectors;
3769
3770 if (display_in_cyl_units && cyl_units)
3771 units_per_sector = cyl_units;
3772 else
3773 units_per_sector = 1; /* in sectors */
3774}
3775
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003776#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003777static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003778warn_cylinders(void)
3779{
Rob Landley5527b912006-02-25 03:46:10 +00003780 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003781 fprintf(stderr, _("\n"
3782"The number of cylinders for this disk is set to %d.\n"
3783"There is nothing wrong with that, but this is larger than 1024,\n"
3784"and could in certain setups cause problems with:\n"
3785"1) software that runs at boot time (e.g., old versions of LILO)\n"
3786"2) booting and partitioning software from other OSs\n"
3787" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3788 cylinders);
3789}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003790#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003791
3792static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003793read_extended(int ext)
3794{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003795 int i;
3796 struct pte *pex;
3797 struct partition *p, *q;
3798
3799 ext_index = ext;
3800 pex = &ptes[ext];
3801 pex->ext_pointer = pex->part_table;
3802
3803 p = pex->part_table;
3804 if (!get_start_sect(p)) {
3805 fprintf(stderr,
3806 _("Bad offset in primary extended partition\n"));
3807 return;
3808 }
3809
Rob Landleyb73451d2006-02-24 16:29:00 +00003810 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003811 struct pte *pe = &ptes[partitions];
3812
3813 if (partitions >= MAXIMUM_PARTS) {
3814 /* This is not a Linux restriction, but
3815 this program uses arrays of size MAXIMUM_PARTS.
3816 Do not try to `improve' this test. */
3817 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003818#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003819 fprintf(stderr,
3820 _("Warning: deleting partitions after %d\n"),
3821 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003822 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003823#endif
3824 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003825 return;
3826 }
3827
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003828 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003829
3830 if (!extended_offset)
3831 extended_offset = get_start_sect(p);
3832
3833 q = p = pt_offset(pe->sectorbuffer, 0);
3834 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003835 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003836 if (pe->ext_pointer)
3837 fprintf(stderr,
3838 _("Warning: extra link "
3839 "pointer in partition table"
3840 " %d\n"), partitions + 1);
3841 else
3842 pe->ext_pointer = p;
3843 } else if (p->sys_ind) {
3844 if (pe->part_table)
3845 fprintf(stderr,
3846 _("Warning: ignoring extra "
3847 "data in partition table"
3848 " %d\n"), partitions + 1);
3849 else
3850 pe->part_table = p;
3851 }
3852 }
3853
3854 /* very strange code here... */
3855 if (!pe->part_table) {
3856 if (q != pe->ext_pointer)
3857 pe->part_table = q;
3858 else
3859 pe->part_table = q + 1;
3860 }
3861 if (!pe->ext_pointer) {
3862 if (q != pe->part_table)
3863 pe->ext_pointer = q;
3864 else
3865 pe->ext_pointer = q + 1;
3866 }
3867
3868 p = pe->ext_pointer;
3869 partitions++;
3870 }
3871
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003872#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003873 /* remove empty links */
3874 remove:
3875 for (i = 4; i < partitions; i++) {
3876 struct pte *pe = &ptes[i];
3877
3878 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003879 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003880 printf("omitting empty partition (%d)\n", i+1);
3881 delete_partition(i);
3882 goto remove; /* numbering changed */
3883 }
3884 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003885#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003886}
3887
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003888#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003889static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003890create_doslabel(void)
3891{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003892 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"));
Rob Landley5527b912006-02-25 03:46:10 +00003898
3899 current_label_type = label_dos;
3900
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003901#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003902 possibly_osf_label = 0;
3903#endif
3904 partitions = 4;
3905
3906 for (i = 510-64; i < 510; i++)
3907 MBRbuffer[i] = 0;
3908 write_part_table_flag(MBRbuffer);
3909 extended_offset = 0;
3910 set_all_unchanged();
3911 set_changed(0);
3912 get_boot(create_empty_dos);
3913}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003914#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003915
3916static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003917get_sectorsize(void)
3918{
Rob Landley736e5252006-02-25 03:36:00 +00003919 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003920 int arg;
3921 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3922 sector_size = arg;
3923 if (sector_size != DEFAULT_SECTOR_SIZE)
3924 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003925 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003926 }
3927}
3928
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003929static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003930get_kernel_geometry(void)
3931{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003932 struct hd_geometry geometry;
3933
3934 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3935 kern_heads = geometry.heads;
3936 kern_sectors = geometry.sectors;
3937 /* never use geometry.cylinders - it is truncated */
3938 }
3939}
3940
3941static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003942get_partition_table_geometry(void)
3943{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003944 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003945 struct partition *p;
3946 int i, h, s, hh, ss;
3947 int first = 1;
3948 int bad = 0;
3949
Eric Andersen3496fdc2006-01-30 23:09:20 +00003950 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003951 return;
3952
3953 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003954 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003955 p = pt_offset(bufp, i);
3956 if (p->sys_ind != 0) {
3957 h = p->end_head + 1;
3958 s = (p->end_sector & 077);
3959 if (first) {
3960 hh = h;
3961 ss = s;
3962 first = 0;
3963 } else if (hh != h || ss != s)
3964 bad = 1;
3965 }
3966 }
3967
3968 if (!first && !bad) {
3969 pt_heads = hh;
3970 pt_sectors = ss;
3971 }
3972}
3973
Rob Landleyb73451d2006-02-24 16:29:00 +00003974static void
3975get_geometry(void)
3976{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003977 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003978 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003979
3980 get_sectorsize();
3981 sec_fac = sector_size / 512;
3982#ifdef CONFIG_FEATURE_SUN_LABEL
3983 guess_device_type();
3984#endif
3985 heads = cylinders = sectors = 0;
3986 kern_heads = kern_sectors = 0;
3987 pt_heads = pt_sectors = 0;
3988
3989 get_kernel_geometry();
3990 get_partition_table_geometry();
3991
3992 heads = user_heads ? user_heads :
3993 pt_heads ? pt_heads :
3994 kern_heads ? kern_heads : 255;
3995 sectors = user_sectors ? user_sectors :
3996 pt_sectors ? pt_sectors :
3997 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003998 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3999 /* got bytes */
4000 } else {
4001 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004002
4003 if (ioctl(fd, BLKGETSIZE, &longsectors))
4004 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004005 bytes = ((unsigned long long) longsectors) << 9;
4006 }
4007
4008 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004009
4010 sector_offset = 1;
4011 if (dos_compatible_flag)
4012 sector_offset = sectors;
4013
Eric Andersen040f4402003-07-30 08:40:37 +00004014 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004015 if (!cylinders)
4016 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004017}
4018
4019/*
4020 * Read MBR. Returns:
4021 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4022 * 0: found or created label
4023 * 1: I/O error
4024 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004025static int
4026get_boot(enum action what)
4027{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004028 int i;
4029
4030 partitions = 4;
4031
4032 for (i = 0; i < 4; i++) {
4033 struct pte *pe = &ptes[i];
4034
4035 pe->part_table = pt_offset(MBRbuffer, i);
4036 pe->ext_pointer = NULL;
4037 pe->offset = 0;
4038 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004039#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004040 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004041#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004042 }
4043
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004044#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004045 if (what == create_empty_sun && check_sun_label())
4046 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004047#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004048
4049 memset(MBRbuffer, 0, 512);
4050
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004051#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004052 if (what == create_empty_dos)
4053 goto got_dos_table; /* skip reading disk */
4054
4055 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004056 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4057 if (what == try_only)
4058 return 1;
4059 fdisk_fatal(unable_to_open);
4060 } else
4061 printf(_("You will not be able to write "
4062 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004063 }
4064
4065 if (512 != read(fd, MBRbuffer, 512)) {
4066 if (what == try_only)
4067 return 1;
4068 fdisk_fatal(unable_to_read);
4069 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004070#else
4071 if ((fd = open(disk_device, O_RDONLY)) < 0)
4072 return 1;
4073 if (512 != read(fd, MBRbuffer, 512))
4074 return 1;
4075#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004076
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004077 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004078
4079 update_units();
4080
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004081#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004082 if (check_sun_label())
4083 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004084#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004085
4086#ifdef CONFIG_FEATURE_SGI_LABEL
4087 if (check_sgi_label())
4088 return 0;
4089#endif
4090
4091#ifdef CONFIG_FEATURE_AIX_LABEL
4092 if (check_aix_label())
4093 return 0;
4094#endif
4095
4096#ifdef CONFIG_FEATURE_OSF_LABEL
4097 if (check_osf_label()) {
4098 possibly_osf_label = 1;
4099 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004100 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004101 return 0;
4102 }
4103 printf(_("This disk has both DOS and BSD magic.\n"
4104 "Give the 'b' command to go to BSD mode.\n"));
4105 }
4106#endif
4107
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004108#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004109 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004110#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004111
4112 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004113#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4114 return -1;
4115#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004116 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004117 case fdisk:
4118 fprintf(stderr,
4119 _("Device contains neither a valid DOS "
4120 "partition table, nor Sun, SGI or OSF "
4121 "disklabel\n"));
4122#ifdef __sparc__
4123#ifdef CONFIG_FEATURE_SUN_LABEL
4124 create_sunlabel();
4125#endif
4126#else
4127 create_doslabel();
4128#endif
4129 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004130 case try_only:
4131 return -1;
4132 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004133#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004134 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004135#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004136 break;
4137 default:
4138 fprintf(stderr, _("Internal error\n"));
4139 exit(1);
4140 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004141#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004142 }
4143
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004144#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004145 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004146#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004147 warn_geometry();
4148
4149 for (i = 0; i < 4; i++) {
4150 struct pte *pe = &ptes[i];
4151
Rob Landleyb73451d2006-02-24 16:29:00 +00004152 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004153 if (partitions != 4)
4154 fprintf(stderr, _("Ignoring extra extended "
4155 "partition %d\n"), i + 1);
4156 else
4157 read_extended(i);
4158 }
4159 }
4160
4161 for (i = 3; i < partitions; i++) {
4162 struct pte *pe = &ptes[i];
4163
4164 if (!valid_part_table_flag(pe->sectorbuffer)) {
4165 fprintf(stderr,
4166 _("Warning: invalid flag 0x%04x of partition "
4167 "table %d will be corrected by w(rite)\n"),
4168 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004169#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004170 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004171#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004172 }
4173 }
4174
4175 return 0;
4176}
4177
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004178#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004179/*
4180 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4181 * If the user hits Enter, DFLT is returned.
4182 * Answers like +10 are interpreted as offsets from BASE.
4183 *
4184 * There is no default if DFLT is not between LOW and HIGH.
4185 */
4186static uint
4187read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4188{
4189 uint i;
4190 int default_ok = 1;
4191 static char *ms = NULL;
4192 static int mslen = 0;
4193
4194 if (!ms || strlen(mesg)+100 > mslen) {
4195 mslen = strlen(mesg)+200;
4196 ms = xrealloc(ms,mslen);
4197 }
4198
4199 if (dflt < low || dflt > high)
4200 default_ok = 0;
4201
4202 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004203 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004204 mesg, low, high, dflt);
4205 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004206 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004207
4208 while (1) {
4209 int use_default = default_ok;
4210
4211 /* ask question and read answer */
4212 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004213 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004214 continue;
4215
Eric Andersen84bdea82004-05-19 10:49:17 +00004216 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004217 int minus = (*line_ptr == '-');
4218 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004219
Rob Landleyb73451d2006-02-24 16:29:00 +00004220 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004221
Rob Landleyb73451d2006-02-24 16:29:00 +00004222 while (isdigit(*++line_ptr))
4223 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004224
Rob Landleyb73451d2006-02-24 16:29:00 +00004225 switch (*line_ptr) {
4226 case 'c':
4227 case 'C':
4228 if (!display_in_cyl_units)
4229 i *= heads * sectors;
4230 break;
4231 case 'K':
4232 absolute = 1024;
4233 break;
4234 case 'k':
4235 absolute = 1000;
4236 break;
4237 case 'm':
4238 case 'M':
4239 absolute = 1000000;
4240 break;
4241 case 'g':
4242 case 'G':
4243 absolute = 1000000000;
4244 break;
4245 default:
4246 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004247 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004248 if (absolute) {
4249 unsigned long long bytes;
4250 unsigned long unit;
4251
4252 bytes = (unsigned long long) i * absolute;
4253 unit = sector_size * units_per_sector;
4254 bytes += unit/2; /* round */
4255 bytes /= unit;
4256 i = bytes;
4257 }
4258 if (minus)
4259 i = -i;
4260 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004261 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004262 i = atoi(line_ptr);
4263 while (isdigit(*line_ptr)) {
4264 line_ptr++;
4265 use_default = 0;
4266 }
4267 }
4268 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004269 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004270 if (i >= low && i <= high)
4271 break;
4272 else
4273 printf(_("Value out of range.\n"));
4274 }
4275 return i;
4276}
4277
Rob Landleyb73451d2006-02-24 16:29:00 +00004278static int
4279get_partition(int warn, int max)
4280{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004281 struct pte *pe;
4282 int i;
4283
4284 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4285 pe = &ptes[i];
4286
4287 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004288 if (
4289 (
4290 label_sun != current_label_type &&
4291 label_sgi != current_label_type &&
4292 !pe->part_table->sys_ind
4293 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004294#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004295 || (
4296 label_sun == current_label_type &&
4297 (
4298 !sunlabel->partitions[i].num_sectors
4299 || !sunlabel->infos[i].id
4300 )
4301 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004302#endif
4303#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004304 || (
4305 label_sgi == current_label_type &&
4306 !sgi_get_num_sectors(i)
4307 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004308#endif
Rob Landley5527b912006-02-25 03:46:10 +00004309 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004310 fprintf(stderr,
4311 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004312 i+1
4313 );
4314 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004315 }
4316 return i;
4317}
4318
4319static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004320get_existing_partition(int warn, int max)
4321{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004322 int pno = -1;
4323 int i;
4324
4325 for (i = 0; i < max; i++) {
4326 struct pte *pe = &ptes[i];
4327 struct partition *p = pe->part_table;
4328
4329 if (p && !is_cleared_partition(p)) {
4330 if (pno >= 0)
4331 goto not_unique;
4332 pno = i;
4333 }
4334 }
4335 if (pno >= 0) {
4336 printf(_("Selected partition %d\n"), pno+1);
4337 return pno;
4338 }
4339 printf(_("No partition is defined yet!\n"));
4340 return -1;
4341
4342 not_unique:
4343 return get_partition(warn, max);
4344}
4345
4346static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004347get_nonexisting_partition(int warn, int max)
4348{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004349 int pno = -1;
4350 int i;
4351
4352 for (i = 0; i < max; i++) {
4353 struct pte *pe = &ptes[i];
4354 struct partition *p = pe->part_table;
4355
4356 if (p && is_cleared_partition(p)) {
4357 if (pno >= 0)
4358 goto not_unique;
4359 pno = i;
4360 }
4361 }
4362 if (pno >= 0) {
4363 printf(_("Selected partition %d\n"), pno+1);
4364 return pno;
4365 }
4366 printf(_("All primary partitions have been defined already!\n"));
4367 return -1;
4368
4369 not_unique:
4370 return get_partition(warn, max);
4371}
4372
4373
4374void change_units(void)
4375{
4376 display_in_cyl_units = !display_in_cyl_units;
4377 update_units();
4378 printf(_("Changing display/entry units to %s\n"),
4379 str_units(PLURAL));
4380}
4381
4382static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004383toggle_active(int i)
4384{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004385 struct pte *pe = &ptes[i];
4386 struct partition *p = pe->part_table;
4387
Rob Landleyb73451d2006-02-24 16:29:00 +00004388 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004389 fprintf(stderr,
4390 _("WARNING: Partition %d is an extended partition\n"),
4391 i + 1);
4392 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4393 pe->changed = 1;
4394}
4395
4396static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004397toggle_dos_compatibility_flag(void)
4398{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004399 dos_compatible_flag = ~dos_compatible_flag;
4400 if (dos_compatible_flag) {
4401 sector_offset = sectors;
4402 printf(_("DOS Compatibility flag is set\n"));
4403 }
4404 else {
4405 sector_offset = 1;
4406 printf(_("DOS Compatibility flag is not set\n"));
4407 }
4408}
4409
4410static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004411delete_partition(int i)
4412{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004413 struct pte *pe = &ptes[i];
4414 struct partition *p = pe->part_table;
4415 struct partition *q = pe->ext_pointer;
4416
4417/* Note that for the fifth partition (i == 4) we don't actually
4418 * decrement partitions.
4419 */
4420
4421 if (warn_geometry())
4422 return; /* C/H/S not set */
4423 pe->changed = 1;
4424
4425#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004426 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004427 sun_delete_partition(i);
4428 return;
4429 }
4430#endif
4431#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004432 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004433 sgi_delete_partition(i);
4434 return;
4435 }
4436#endif
4437
4438 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004439 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004440 partitions = 4;
4441 ptes[ext_index].ext_pointer = NULL;
4442 extended_offset = 0;
4443 }
4444 clear_partition(p);
4445 return;
4446 }
4447
4448 if (!q->sys_ind && i > 4) {
4449 /* the last one in the chain - just delete */
4450 --partitions;
4451 --i;
4452 clear_partition(ptes[i].ext_pointer);
4453 ptes[i].changed = 1;
4454 } else {
4455 /* not the last one - further ones will be moved down */
4456 if (i > 4) {
4457 /* delete this link in the chain */
4458 p = ptes[i-1].ext_pointer;
4459 *p = *q;
4460 set_start_sect(p, get_start_sect(q));
4461 set_nr_sects(p, get_nr_sects(q));
4462 ptes[i-1].changed = 1;
4463 } else if (partitions > 5) { /* 5 will be moved to 4 */
4464 /* the first logical in a longer chain */
4465 pe = &ptes[5];
4466
4467 if (pe->part_table) /* prevent SEGFAULT */
4468 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004469 get_partition_start(pe) -
4470 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004471 pe->offset = extended_offset;
4472 pe->changed = 1;
4473 }
4474
4475 if (partitions > 5) {
4476 partitions--;
4477 while (i < partitions) {
4478 ptes[i] = ptes[i+1];
4479 i++;
4480 }
4481 } else
4482 /* the only logical: clear only */
4483 clear_partition(ptes[i].part_table);
4484 }
4485}
4486
4487static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004488change_sysid(void)
4489{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004490 int i, sys, origsys;
4491 struct partition *p;
4492
Eric Andersen040f4402003-07-30 08:40:37 +00004493#ifdef CONFIG_FEATURE_SGI_LABEL
4494 /* If sgi_label then don't use get_existing_partition,
4495 let the user select a partition, since get_existing_partition()
4496 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004497 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004498 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004499 } else {
4500 i = get_partition(0, partitions);
4501 }
4502#else
4503 i = get_existing_partition(0, partitions);
4504#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004505 if (i == -1)
4506 return;
4507 p = ptes[i].part_table;
4508 origsys = sys = get_sysid(i);
4509
4510 /* if changing types T to 0 is allowed, then
4511 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004512 if (!sys && label_sgi != current_label_type &&
4513 label_sun != current_label_type && !get_nr_sects(p))
4514 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004515 printf(_("Partition %d does not exist yet!\n"), i + 1);
Rob Landley5527b912006-02-25 03:46:10 +00004516 }else{
4517 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004518 sys = read_hex (get_sys_types());
4519
Rob Landley5527b912006-02-25 03:46:10 +00004520 if (!sys && label_sgi != current_label_type &&
4521 label_sun != current_label_type)
4522 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004523 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004524 "(but not to Linux). Having partitions of\n"
4525 "type 0 is probably unwise. You can delete\n"
4526 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004527 /* break; */
4528 }
4529
Rob Landley5527b912006-02-25 03:46:10 +00004530 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004531 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004532 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004533 " an extended one or vice versa\n"
4534 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004535 break;
4536 }
4537 }
4538
4539 if (sys < 256) {
4540#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004541 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004542 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004543 "as Whole disk (5),\n"
4544 "as SunOS/Solaris expects it and "
4545 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004546#endif
4547#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004548 if (label_sgi == current_label_type &&
4549 (
4550 (i == 10 && sys != ENTIRE_DISK) ||
4551 (i == 8 && sys != 0)
4552 )
4553 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004554 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004555 "as volume header (0),\nand "
4556 "partition 11 as entire volume (6)"
4557 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004558 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004559#endif
4560 if (sys == origsys)
4561 break;
4562#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004563 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004564 sun_change_sysid(i, sys);
4565 } else
4566#endif
4567#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004568 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004569 sgi_change_sysid(i, sys);
4570 } else
4571#endif
4572 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004573
Rob Landleyb73451d2006-02-24 16:29:00 +00004574 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004575 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004576 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004577 ptes[i].changed = 1;
4578 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004579 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004580 dos_changed = 1;
4581 break;
4582 }
Rob Landley5527b912006-02-25 03:46:10 +00004583 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004584 }
4585}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004586#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4587
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004588
4589/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4590 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4591 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4592 * Lubkin Oct. 1991). */
4593
Rob Landleyb73451d2006-02-24 16:29:00 +00004594static void
4595long2chs(ulong ls, uint *c, uint *h, uint *s)
4596{
4597 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004598
4599 *c = ls / spc;
4600 ls = ls % spc;
4601 *h = ls / sectors;
4602 *s = ls % sectors + 1; /* sectors count from 1 */
4603}
4604
Rob Landleyb73451d2006-02-24 16:29:00 +00004605static void
4606check_consistency(const struct partition *p, int partition)
4607{
4608 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4609 uint pec, peh, pes; /* physical ending c, h, s */
4610 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4611 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004612
4613 if (!heads || !sectors || (partition >= 4))
4614 return; /* do not check extended partitions */
4615
4616/* physical beginning c, h, s */
4617 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4618 pbh = p->head;
4619 pbs = p->sector & 0x3f;
4620
4621/* physical ending c, h, s */
4622 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4623 peh = p->end_head;
4624 pes = p->end_sector & 0x3f;
4625
4626/* compute logical beginning (c, h, s) */
4627 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4628
4629/* compute logical ending (c, h, s) */
4630 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4631
4632/* Same physical / logical beginning? */
4633 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4634 printf(_("Partition %d has different physical/logical "
4635 "beginnings (non-Linux?):\n"), partition + 1);
4636 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4637 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4638 }
4639
4640/* Same physical / logical ending? */
4641 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4642 printf(_("Partition %d has different physical/logical "
4643 "endings:\n"), partition + 1);
4644 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4645 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4646 }
4647
4648#if 0
4649/* Beginning on cylinder boundary? */
4650 if (pbh != !pbc || pbs != 1) {
4651 printf(_("Partition %i does not start on cylinder "
4652 "boundary:\n"), partition + 1);
4653 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4654 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4655 }
4656#endif
4657
4658/* Ending on cylinder boundary? */
4659 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004660 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004661 partition + 1);
4662#if 0
4663 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4664 printf(_("should be (%d, %d, %d)\n"),
4665 pec, heads - 1, sectors);
4666#endif
4667 }
4668}
4669
4670static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004671list_disk_geometry(void)
4672{
Eric Andersen040f4402003-07-30 08:40:37 +00004673 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004674 long megabytes = bytes/1000000;
4675
4676 if (megabytes < 10000)
4677 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004678 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004679 else
4680 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004681 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004682 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004683 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004684 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004685 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004686 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004687 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004688 str_units(PLURAL),
4689 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004690}
4691
4692/*
4693 * Check whether partition entries are ordered by their starting positions.
4694 * Return 0 if OK. Return i if partition i should have been earlier.
4695 * Two separate checks: primary and logical partitions.
4696 */
4697static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004698wrong_p_order(int *prev)
4699{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004700 const struct pte *pe;
4701 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004702 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004703 int i, last_i = 0;
4704
4705 for (i = 0 ; i < partitions; i++) {
4706 if (i == 4) {
4707 last_i = 4;
4708 last_p_start_pos = 0;
4709 }
4710 pe = &ptes[i];
4711 if ((p = pe->part_table)->sys_ind) {
4712 p_start_pos = get_partition_start(pe);
4713
4714 if (last_p_start_pos > p_start_pos) {
4715 if (prev)
4716 *prev = last_i;
4717 return i;
4718 }
4719
4720 last_p_start_pos = p_start_pos;
4721 last_i = i;
4722 }
4723 }
4724 return 0;
4725}
4726
4727#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4728/*
4729 * Fix the chain of logicals.
4730 * extended_offset is unchanged, the set of sectors used is unchanged
4731 * The chain is sorted so that sectors increase, and so that
4732 * starting sectors increase.
4733 *
4734 * After this it may still be that cfdisk doesnt like the table.
4735 * (This is because cfdisk considers expanded parts, from link to
4736 * end of partition, and these may still overlap.)
4737 * Now
4738 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4739 * may help.
4740 */
4741static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004742fix_chain_of_logicals(void)
4743{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004744 int j, oj, ojj, sj, sjj;
4745 struct partition *pj,*pjj,tmp;
4746
4747 /* Stage 1: sort sectors but leave sector of part 4 */
4748 /* (Its sector is the global extended_offset.) */
4749 stage1:
4750 for (j = 5; j < partitions-1; j++) {
4751 oj = ptes[j].offset;
4752 ojj = ptes[j+1].offset;
4753 if (oj > ojj) {
4754 ptes[j].offset = ojj;
4755 ptes[j+1].offset = oj;
4756 pj = ptes[j].part_table;
4757 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4758 pjj = ptes[j+1].part_table;
4759 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4760 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004761 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004762 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004763 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004764 goto stage1;
4765 }
4766 }
4767
4768 /* Stage 2: sort starting sectors */
4769 stage2:
4770 for (j = 4; j < partitions-1; j++) {
4771 pj = ptes[j].part_table;
4772 pjj = ptes[j+1].part_table;
4773 sj = get_start_sect(pj);
4774 sjj = get_start_sect(pjj);
4775 oj = ptes[j].offset;
4776 ojj = ptes[j+1].offset;
4777 if (oj+sj > ojj+sjj) {
4778 tmp = *pj;
4779 *pj = *pjj;
4780 *pjj = tmp;
4781 set_start_sect(pj, ojj+sjj-oj);
4782 set_start_sect(pjj, oj+sj-ojj);
4783 goto stage2;
4784 }
4785 }
4786
4787 /* Probably something was changed */
4788 for (j = 4; j < partitions; j++)
4789 ptes[j].changed = 1;
4790}
4791
4792
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004793static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004794fix_partition_table_order(void)
4795{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004796 struct pte *pei, *pek;
4797 int i,k;
4798
4799 if (!wrong_p_order(NULL)) {
4800 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4801 return;
4802 }
4803
4804 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4805 /* partition i should have come earlier, move it */
4806 /* We have to move data in the MBR */
4807 struct partition *pi, *pk, *pe, pbuf;
4808 pei = &ptes[i];
4809 pek = &ptes[k];
4810
4811 pe = pei->ext_pointer;
4812 pei->ext_pointer = pek->ext_pointer;
4813 pek->ext_pointer = pe;
4814
4815 pi = pei->part_table;
4816 pk = pek->part_table;
4817
4818 memmove(&pbuf, pi, sizeof(struct partition));
4819 memmove(pi, pk, sizeof(struct partition));
4820 memmove(pk, &pbuf, sizeof(struct partition));
4821
4822 pei->changed = pek->changed = 1;
4823 }
4824
4825 if (i)
4826 fix_chain_of_logicals();
4827
4828 printf("Done.\n");
4829
4830}
4831#endif
4832
4833static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004834list_table(int xtra)
4835{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004836 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004837 int i, w;
4838
4839#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004840 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004841 sun_list_table(xtra);
4842 return;
4843 }
4844#endif
4845
4846#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004847 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004848 sgi_list_table(xtra);
4849 return;
4850 }
4851#endif
4852
4853 list_disk_geometry();
4854
4855#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004856 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004857 xbsd_print_disklabel(xtra);
4858 return;
4859 }
4860#endif
4861
4862 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4863 but if the device name ends in a digit, say /dev/foo1,
4864 then the partition is called /dev/foo1p3. */
4865 w = strlen(disk_device);
4866 if (w && isdigit(disk_device[w-1]))
4867 w++;
4868 if (w < 5)
4869 w = 5;
4870
4871 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004872 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004873
4874 for (i = 0; i < partitions; i++) {
4875 const struct pte *pe = &ptes[i];
4876
4877 p = pe->part_table;
4878 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004879 off_t psects = get_nr_sects(p);
4880 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004881 unsigned int podd = 0;
4882
4883 if (sector_size < 1024) {
4884 pblocks /= (1024 / sector_size);
4885 podd = psects % (1024 / sector_size);
4886 }
4887 if (sector_size > 1024)
4888 pblocks *= (sector_size / 1024);
4889 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004890 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004891 partname(disk_device, i+1, w+2),
4892/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4893 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004894/* start */ (unsigned long long) cround(get_partition_start(pe)),
4895/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004896 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004897/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004898/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004899/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004900 check_consistency(p, i);
4901 }
4902 }
4903
4904 /* Is partition table in disk order? It need not be, but... */
4905 /* partition table entries are not checked for correct order if this
4906 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004907 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4908 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004909 printf(_("\nPartition table entries are not in disk order\n"));
4910 }
4911}
4912
4913#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4914static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004915x_list_table(int extend)
4916{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004917 const struct pte *pe;
4918 const struct partition *p;
4919 int i;
4920
4921 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4922 disk_device, heads, sectors, cylinders);
4923 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4924 for (i = 0 ; i < partitions; i++) {
4925 pe = &ptes[i];
4926 p = (extend ? pe->ext_pointer : pe->part_table);
4927 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004928 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004929 i + 1, p->boot_ind, p->head,
4930 sector(p->sector),
4931 cylinder(p->sector, p->cyl), p->end_head,
4932 sector(p->end_sector),
4933 cylinder(p->end_sector, p->end_cyl),
4934 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4935 if (p->sys_ind)
4936 check_consistency(p, i);
4937 }
4938 }
4939}
4940#endif
4941
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004942#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004943static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004944fill_bounds(off_t *first, off_t *last)
4945{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004946 int i;
4947 const struct pte *pe = &ptes[0];
4948 const struct partition *p;
4949
4950 for (i = 0; i < partitions; pe++,i++) {
4951 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004952 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004953 first[i] = 0xffffffff;
4954 last[i] = 0;
4955 } else {
4956 first[i] = get_partition_start(pe);
4957 last[i] = first[i] + get_nr_sects(p) - 1;
4958 }
4959 }
4960}
4961
4962static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004963check(int n, uint h, uint s, uint c, off_t start)
4964{
Eric Andersend9261492004-06-28 23:50:31 +00004965 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004966
4967 real_s = sector(s) - 1;
4968 real_c = cylinder(s, c);
4969 total = (real_c * sectors + real_s) * heads + h;
4970 if (!total)
4971 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4972 if (h >= heads)
4973 fprintf(stderr,
4974 _("Partition %d: head %d greater than maximum %d\n"),
4975 n, h + 1, heads);
4976 if (real_s >= sectors)
4977 fprintf(stderr, _("Partition %d: sector %d greater than "
4978 "maximum %d\n"), n, s, sectors);
4979 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004980 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4981 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004982 if (cylinders <= 1024 && start != total)
4983 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004984 _("Partition %d: previous sectors %llu disagrees with "
4985 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004986}
4987
4988static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004989verify(void)
4990{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004991 int i, j;
4992 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00004993 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004994 struct partition *p;
4995
4996 if (warn_geometry())
4997 return;
4998
4999#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005000 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005001 verify_sun();
5002 return;
5003 }
5004#endif
5005#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005006 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005007 verify_sgi(1);
5008 return;
5009 }
5010#endif
5011
5012 fill_bounds(first, last);
5013 for (i = 0; i < partitions; i++) {
5014 struct pte *pe = &ptes[i];
5015
5016 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005017 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005018 check_consistency(p, i);
5019 if (get_partition_start(pe) < first[i])
5020 printf(_("Warning: bad start-of-data in "
5021 "partition %d\n"), i + 1);
5022 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5023 last[i]);
5024 total += last[i] + 1 - first[i];
5025 for (j = 0; j < i; j++)
5026 if ((first[i] >= first[j] && first[i] <= last[j])
5027 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5028 printf(_("Warning: partition %d overlaps "
5029 "partition %d.\n"), j + 1, i + 1);
5030 total += first[i] >= first[j] ?
5031 first[i] : first[j];
5032 total -= last[i] <= last[j] ?
5033 last[i] : last[j];
5034 }
5035 }
5036 }
5037
5038 if (extended_offset) {
5039 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005040 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005041 get_nr_sects(pex->part_table) - 1;
5042
5043 for (i = 4; i < partitions; i++) {
5044 total++;
5045 p = ptes[i].part_table;
5046 if (!p->sys_ind) {
5047 if (i != 4 || i + 1 < partitions)
5048 printf(_("Warning: partition %d "
5049 "is empty\n"), i + 1);
5050 }
5051 else if (first[i] < extended_offset ||
5052 last[i] > e_last)
5053 printf(_("Logical partition %d not entirely in "
5054 "partition %d\n"), i + 1, ext_index + 1);
5055 }
5056 }
5057
5058 if (total > heads * sectors * cylinders)
5059 printf(_("Total allocated sectors %d greater than the maximum "
5060 "%d\n"), total, heads * sectors * cylinders);
5061 else if ((total = heads * sectors * cylinders - total) != 0)
5062 printf(_("%d unallocated sectors\n"), total);
5063}
5064
5065static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005066add_partition(int n, int sys)
5067{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005068 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005069 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005070 struct partition *p = ptes[n].part_table;
5071 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005072 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005073 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005074 first[partitions], last[partitions];
5075
5076 if (p && p->sys_ind) {
5077 printf(_("Partition %d is already defined. Delete "
5078 "it before re-adding it.\n"), n + 1);
5079 return;
5080 }
5081 fill_bounds(first, last);
5082 if (n < 4) {
5083 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005084 if (display_in_cyl_units || !total_number_of_sectors)
5085 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005086 else
Eric Andersen040f4402003-07-30 08:40:37 +00005087 llimit = total_number_of_sectors - 1;
5088 limit = llimit;
5089 if (limit != llimit)
5090 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005091 if (extended_offset) {
5092 first[ext_index] = extended_offset;
5093 last[ext_index] = get_start_sect(q) +
5094 get_nr_sects(q) - 1;
5095 }
5096 } else {
5097 start = extended_offset + sector_offset;
5098 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5099 }
5100 if (display_in_cyl_units)
5101 for (i = 0; i < partitions; i++)
5102 first[i] = (cround(first[i]) - 1) * units_per_sector;
5103
5104 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5105 do {
5106 temp = start;
5107 for (i = 0; i < partitions; i++) {
5108 int lastplusoff;
5109
5110 if (start == ptes[i].offset)
5111 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005112 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005113 if (start >= first[i] && start <= lastplusoff)
5114 start = lastplusoff + 1;
5115 }
5116 if (start > limit)
5117 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005118 if (start >= temp+units_per_sector && num_read) {
Eric Andersend9261492004-06-28 23:50:31 +00005119 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005120 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005121 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005122 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005123 if (!num_read && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005124 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005125
5126 saved_start = start;
5127 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5128 0, mesg);
5129 if (display_in_cyl_units) {
5130 start = (start - 1) * units_per_sector;
5131 if (start < saved_start) start = saved_start;
5132 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005133 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005134 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005135 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005136 if (n > 4) { /* NOT for fifth partition */
5137 struct pte *pe = &ptes[n];
5138
5139 pe->offset = start - sector_offset;
5140 if (pe->offset == extended_offset) { /* must be corrected */
5141 pe->offset++;
5142 if (sector_offset == 1)
5143 start++;
5144 }
5145 }
5146
5147 for (i = 0; i < partitions; i++) {
5148 struct pte *pe = &ptes[i];
5149
5150 if (start < pe->offset && limit >= pe->offset)
5151 limit = pe->offset - 1;
5152 if (start < first[i] && limit >= first[i])
5153 limit = first[i] - 1;
5154 }
5155 if (start > limit) {
5156 printf(_("No free sectors available\n"));
5157 if (n > 4)
5158 partitions--;
5159 return;
5160 }
5161 if (cround(start) == cround(limit)) {
5162 stop = limit;
5163 } else {
5164 snprintf(mesg, sizeof(mesg),
5165 _("Last %s or +size or +sizeM or +sizeK"),
5166 str_units(SINGULAR));
5167 stop = read_int(cround(start), cround(limit), cround(limit),
5168 cround(start), mesg);
5169 if (display_in_cyl_units) {
5170 stop = stop * units_per_sector - 1;
5171 if (stop >limit)
5172 stop = limit;
5173 }
5174 }
5175
5176 set_partition(n, 0, start, stop, sys);
5177 if (n > 4)
5178 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5179
Rob Landleyb73451d2006-02-24 16:29:00 +00005180 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005181 struct pte *pe4 = &ptes[4];
5182 struct pte *pen = &ptes[n];
5183
5184 ext_index = n;
5185 pen->ext_pointer = p;
5186 pe4->offset = extended_offset = start;
5187 pe4->sectorbuffer = xcalloc(1, sector_size);
5188 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5189 pe4->ext_pointer = pe4->part_table + 1;
5190 pe4->changed = 1;
5191 partitions = 5;
5192 }
5193}
5194
5195static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005196add_logical(void)
5197{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005198 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5199 struct pte *pe = &ptes[partitions];
5200
5201 pe->sectorbuffer = xcalloc(1, sector_size);
5202 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5203 pe->ext_pointer = pe->part_table + 1;
5204 pe->offset = 0;
5205 pe->changed = 1;
5206 partitions++;
5207 }
5208 add_partition(partitions - 1, LINUX_NATIVE);
5209}
5210
5211static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005212new_partition(void)
5213{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005214 int i, free_primary = 0;
5215
5216 if (warn_geometry())
5217 return;
5218
5219#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005220 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005221 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5222 return;
5223 }
5224#endif
5225#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005226 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005227 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5228 return;
5229 }
5230#endif
5231#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005232 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005233 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5234 "\n\tIf you want to add DOS-type partitions, create"
5235 "\n\ta new empty DOS partition table first. (Use o.)"
5236 "\n\tWARNING: "
5237 "This will destroy the present disk contents.\n"));
5238 return;
5239 }
5240#endif
5241
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005242 for (i = 0; i < 4; i++)
5243 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005244
Rob Landleyb73451d2006-02-24 16:29:00 +00005245 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005246 printf(_("The maximum number of partitions has been created\n"));
5247 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005248 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005249
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005250 if (!free_primary) {
5251 if (extended_offset)
5252 add_logical();
5253 else
5254 printf(_("You must delete some partition and add "
5255 "an extended partition first\n"));
5256 } else {
5257 char c, line[LINE_LENGTH];
5258 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5259 "partition (1-4)\n",
5260 "Command action", (extended_offset ?
5261 "l logical (5 or over)" : "e extended"));
5262 while (1) {
5263 if ((c = read_char(line)) == 'p' || c == 'P') {
5264 i = get_nonexisting_partition(0, 4);
5265 if (i >= 0)
5266 add_partition(i, LINUX_NATIVE);
5267 return;
5268 }
5269 else if (c == 'l' && extended_offset) {
5270 add_logical();
5271 return;
5272 }
5273 else if (c == 'e' && !extended_offset) {
5274 i = get_nonexisting_partition(0, 4);
5275 if (i >= 0)
5276 add_partition(i, EXTENDED);
5277 return;
5278 }
5279 else
5280 printf(_("Invalid partition number "
5281 "for type `%c'\n"), c);
5282 }
5283 }
5284}
5285
5286static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005287write_table(void)
5288{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005289 int i;
5290
Rob Landley5527b912006-02-25 03:46:10 +00005291 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005292 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005293 if (ptes[i].changed)
5294 ptes[3].changed = 1;
5295 for (i = 3; i < partitions; i++) {
5296 struct pte *pe = &ptes[i];
5297
5298 if (pe->changed) {
5299 write_part_table_flag(pe->sectorbuffer);
5300 write_sector(pe->offset, pe->sectorbuffer);
5301 }
5302 }
5303 }
5304#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005305 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005306 /* no test on change? the printf below might be mistaken */
5307 sgi_write_table();
5308 }
5309#endif
5310#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005311 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005312 int needw = 0;
5313
Rob Landleyb73451d2006-02-24 16:29:00 +00005314 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005315 if (ptes[i].changed)
5316 needw = 1;
5317 if (needw)
5318 sun_write_table();
5319 }
5320#endif
5321
5322 printf(_("The partition table has been altered!\n\n"));
5323 reread_partition_table(1);
5324}
5325
Rob Landleyb73451d2006-02-24 16:29:00 +00005326static void
5327reread_partition_table(int leave)
5328{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005329 int error = 0;
5330 int i;
5331
5332 printf(_("Calling ioctl() to re-read partition table.\n"));
5333 sync();
5334 sleep(2);
5335 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5336 error = errno;
5337 } else {
5338 /* some kernel versions (1.2.x) seem to have trouble
5339 rereading the partition table, but if asked to do it
5340 twice, the second time works. - biro@yggdrasil.com */
5341 sync();
5342 sleep(2);
5343 if ((i = ioctl(fd, BLKRRPART)) != 0)
5344 error = errno;
5345 }
5346
5347 if (i) {
5348 printf(_("\nWARNING: Re-reading the partition table "
5349 "failed with error %d: %s.\n"
5350 "The kernel still uses the old table.\n"
5351 "The new table will be used "
5352 "at the next reboot.\n"),
5353 error, strerror(error));
5354 }
5355
5356 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005357 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005358 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5359 "partitions, please see the fdisk manual page for additional\n"
5360 "information.\n"));
5361
5362 if (leave) {
5363 close(fd);
5364
5365 printf(_("Syncing disks.\n"));
5366 sync();
5367 sleep(4); /* for sync() */
5368 exit(!!i);
5369 }
5370}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005371#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005372
5373#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5374#define MAX_PER_LINE 16
5375static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005376print_buffer(char *pbuffer)
5377{
5378 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005379
5380 for (i = 0, l = 0; i < sector_size; i++, l++) {
5381 if (l == 0)
5382 printf("0x%03X:", i);
5383 printf(" %02X", (unsigned char) pbuffer[i]);
5384 if (l == MAX_PER_LINE - 1) {
5385 printf("\n");
5386 l = -1;
5387 }
5388 }
5389 if (l > 0)
5390 printf("\n");
5391 printf("\n");
5392}
5393
5394
5395static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005396print_raw(void)
5397{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005398 int i;
5399
5400 printf(_("Device: %s\n"), disk_device);
5401#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005402 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005403 print_buffer(MBRbuffer);
5404 else
5405#endif
5406 for (i = 3; i < partitions; i++)
5407 print_buffer(ptes[i].sectorbuffer);
5408}
5409
5410static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005411move_begin(int i)
5412{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005413 struct pte *pe = &ptes[i];
5414 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005415 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005416
5417 if (warn_geometry())
5418 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005419 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005420 printf(_("Partition %d has no data area\n"), i + 1);
5421 return;
5422 }
5423 first = get_partition_start(pe);
5424 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005425 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005426
5427 if (new != get_nr_sects(p)) {
5428 first = get_nr_sects(p) + get_start_sect(p) - new;
5429 set_nr_sects(p, first);
5430 set_start_sect(p, new);
5431 pe->changed = 1;
5432 }
5433}
5434
5435static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005436xselect(void)
5437{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005438 char c;
5439
Rob Landleyb73451d2006-02-24 16:29:00 +00005440 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005441 putchar('\n');
5442 c = tolower(read_char(_("Expert command (m for help): ")));
5443 switch (c) {
5444 case 'a':
5445#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005446 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005447 sun_set_alt_cyl();
5448#endif
5449 break;
5450 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005451 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005452 move_begin(get_partition(0, partitions));
5453 break;
5454 case 'c':
5455 user_cylinders = cylinders =
5456 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005457 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005458#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005459 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005460 sun_set_ncyl(cylinders);
5461#endif
Rob Landley5527b912006-02-25 03:46:10 +00005462 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005463 warn_cylinders();
5464 break;
5465 case 'd':
5466 print_raw();
5467 break;
5468 case 'e':
5469#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005470 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005471 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005472 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005473#endif
5474#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005475 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005476 sun_set_xcyl();
5477 else
5478#endif
Rob Landley5527b912006-02-25 03:46:10 +00005479 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005480 x_list_table(1);
5481 break;
5482 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005483 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005484 fix_partition_table_order();
5485 break;
5486 case 'g':
5487#ifdef CONFIG_FEATURE_SGI_LABEL
5488 create_sgilabel();
5489#endif
5490 break;
5491 case 'h':
5492 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005493 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005494 update_units();
5495 break;
5496 case 'i':
5497#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005498 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005499 sun_set_ilfact();
5500#endif
5501 break;
5502 case 'o':
5503#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005504 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005505 sun_set_rspeed();
5506#endif
5507 break;
5508 case 'p':
5509#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005510 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005511 list_table(1);
5512 else
5513#endif
5514 x_list_table(0);
5515 break;
5516 case 'q':
5517 close(fd);
5518 printf("\n");
5519 exit(0);
5520 case 'r':
5521 return;
5522 case 's':
5523 user_sectors = sectors = read_int(1, sectors, 63, 0,
5524 _("Number of sectors"));
5525 if (dos_compatible_flag) {
5526 sector_offset = sectors;
5527 fprintf(stderr, _("Warning: setting "
5528 "sector offset for DOS "
5529 "compatiblity\n"));
5530 }
5531 update_units();
5532 break;
5533 case 'v':
5534 verify();
5535 break;
5536 case 'w':
5537 write_table(); /* does not return */
5538 break;
5539 case 'y':
5540#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005541 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005542 sun_set_pcylcount();
5543#endif
5544 break;
5545 default:
5546 xmenu();
5547 }
5548 }
5549}
5550#endif /* ADVANCED mode */
5551
5552static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005553is_ide_cdrom_or_tape(const char *device)
5554{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005555 FILE *procf;
5556 char buf[100];
5557 struct stat statbuf;
5558 int is_ide = 0;
5559
5560 /* No device was given explicitly, and we are trying some
5561 likely things. But opening /dev/hdc may produce errors like
5562 "hdc: tray open or drive not ready"
5563 if it happens to be a CD-ROM drive. It even happens that
5564 the process hangs on the attempt to read a music CD.
5565 So try to be careful. This only works since 2.1.73. */
5566
5567 if (strncmp("/dev/hd", device, 7))
5568 return 0;
5569
5570 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5571 procf = fopen(buf, "r");
5572 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5573 is_ide = (!strncmp(buf, "cdrom", 5) ||
5574 !strncmp(buf, "tape", 4));
5575 else
5576 /* Now when this proc file does not exist, skip the
5577 device when it is read-only. */
5578 if (stat(device, &statbuf) == 0)
5579 is_ide = ((statbuf.st_mode & 0222) == 0);
5580
5581 if (procf)
5582 fclose(procf);
5583 return is_ide;
5584}
5585
Rob Landley5527b912006-02-25 03:46:10 +00005586
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005587static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005588try(const char *device, int user_specified)
5589{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005590 int gb;
5591
5592 disk_device = device;
5593 if (setjmp(listingbuf))
5594 return;
5595 if (!user_specified)
5596 if (is_ide_cdrom_or_tape(device))
5597 return;
5598 if ((fd = open(disk_device, type_open)) >= 0) {
5599 gb = get_boot(try_only);
5600 if (gb > 0) { /* I/O error */
5601 close(fd);
5602 } else if (gb < 0) { /* no DOS signature */
5603 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005604 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005605 return;
Rob Landley5527b912006-02-25 03:46:10 +00005606 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005607#ifdef CONFIG_FEATURE_OSF_LABEL
5608 if (btrydev(device) < 0)
5609#endif
5610 fprintf(stderr,
5611 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005612 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005613 close(fd);
5614 } else {
5615 close(fd);
5616 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005617#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005618 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005619 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005620 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005621#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005622 }
5623 } else {
5624 /* Ignore other errors, since we try IDE
5625 and SCSI hard disks which may not be
5626 installed on the system. */
5627 if (errno == EACCES) {
5628 fprintf(stderr, _("Cannot open %s\n"), device);
5629 return;
5630 }
5631 }
5632}
5633
5634/* for fdisk -l: try all things in /proc/partitions
5635 that look like a partition name (do not end in a digit) */
5636static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005637tryprocpt(void)
5638{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005639 FILE *procpt;
5640 char line[100], ptname[100], devname[120], *s;
5641 int ma, mi, sz;
5642
Manuel Novoa III cad53642003-03-19 09:13:01 +00005643 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005644
5645 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005646 if (sscanf(line, " %d %d %d %[^\n ]",
5647 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005648 continue;
5649 for (s = ptname; *s; s++);
5650 if (isdigit(s[-1]))
5651 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005652 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005653 try(devname, 0);
5654 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005655#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005656 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005657#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005658}
5659
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005660#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005661static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005662unknown_command(int c)
5663{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005664 printf(_("%c: unknown command\n"), c);
5665}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005666#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005667
Rob Landleyb73451d2006-02-24 16:29:00 +00005668int fdisk_main(int argc, char **argv)
5669{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005670 int c;
5671#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5672 int optl = 0;
5673#endif
5674#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5675 int opts = 0;
5676#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005677 /*
5678 * Calls:
5679 * fdisk -v
5680 * fdisk -l [-b sectorsize] [-u] device ...
5681 * fdisk -s [partition] ...
5682 * fdisk [-b sectorsize] [-u] device
5683 *
5684 * Options -C, -H, -S set the geometry.
5685 *
5686 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005687 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5688#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5689 "s"
5690#endif
5691 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005692 switch (c) {
5693 case 'b':
5694 /* Ugly: this sector size is really per device,
5695 so cannot be combined with multiple disks,
5696 and te same goes for the C/H/S options.
5697 */
5698 sector_size = atoi(optarg);
5699 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005700 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005701 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005702 sector_offset = 2;
5703 user_set_sector_size = 1;
5704 break;
5705 case 'C':
5706 user_cylinders = atoi(optarg);
5707 break;
5708 case 'H':
5709 user_heads = atoi(optarg);
5710 if (user_heads <= 0 || user_heads >= 256)
5711 user_heads = 0;
5712 break;
5713 case 'S':
5714 user_sectors = atoi(optarg);
5715 if (user_sectors <= 0 || user_sectors >= 64)
5716 user_sectors = 0;
5717 break;
5718 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005719#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005720 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005721#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005722 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005723#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005724 case 's':
5725 opts = 1;
5726 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005727#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005728 case 'u':
5729 display_in_cyl_units = 0;
5730 break;
5731 case 'V':
5732 case 'v':
5733 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5734 return 0;
5735 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005736 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005737 }
5738 }
5739
5740#if 0
5741 printf(_("This kernel finds the sector size itself - "
5742 "-b option ignored\n"));
5743#else
5744 if (user_set_sector_size && argc-optind != 1)
5745 printf(_("Warning: the -b (set sector size) option should"
5746 " be used with one specified device\n"));
5747#endif
5748
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005749#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005750 if (optl) {
5751 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005752#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005753 type_open = O_RDONLY;
5754 if (argc > optind) {
5755 int k;
5756#if __GNUC__
5757 /* avoid gcc warning:
5758 variable `k' might be clobbered by `longjmp' */
5759 (void)&k;
5760#endif
5761 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005762 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005763 try(argv[k], 1);
5764 } else {
5765 /* we no longer have default device names */
5766 /* but, we can use /proc/partitions instead */
5767 tryprocpt();
5768 }
5769 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005770#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005771 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005772#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005773
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005774#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005775 if (opts) {
5776 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005777 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005778
5779 nowarn = 1;
5780 type_open = O_RDONLY;
5781
5782 opts = argc - optind;
5783 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005784 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005785
5786 for (j = optind; j < argc; j++) {
5787 disk_device = argv[j];
5788 if ((fd = open(disk_device, type_open)) < 0)
5789 fdisk_fatal(unable_to_open);
5790 if (ioctl(fd, BLKGETSIZE, &size))
5791 fdisk_fatal(ioctl_error);
5792 close(fd);
5793 if (opts == 1)
5794 printf("%ld\n", size/2);
5795 else
5796 printf("%s: %ld\n", argv[j], size/2);
5797 }
5798 return 0;
5799 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005800#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005801
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005802#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005803 if (argc-optind == 1)
5804 disk_device = argv[optind];
5805 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005806 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005807
5808 get_boot(fdisk);
5809
5810#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005811 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005812 /* OSF label, and no DOS label */
5813 printf(_("Detected an OSF/1 disklabel on %s, entering "
5814 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005815 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005816 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005817 /*Why do we do this? It seems to be counter-intuitive*/
5818 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005819 /* If we return we may want to make an empty DOS label? */
5820 }
5821#endif
5822
5823 while (1) {
5824 putchar('\n');
5825 c = tolower(read_char(_("Command (m for help): ")));
5826 switch (c) {
5827 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005828 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005829 toggle_active(get_partition(1, partitions));
5830#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005831 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005832 toggle_sunflags(get_partition(1, partitions),
5833 0x01);
5834#endif
5835#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005836 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005837 sgi_set_bootpartition(
5838 get_partition(1, partitions));
5839#endif
5840 else
5841 unknown_command(c);
5842 break;
5843 case 'b':
5844#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005845 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005846 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005847 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005848 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005849 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005850 printf(_("Boot file unchanged\n"));
5851 else
5852 sgi_set_bootfile(line_ptr);
5853 } else
5854#endif
5855#ifdef CONFIG_FEATURE_OSF_LABEL
5856 bselect();
5857#endif
5858 break;
5859 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005860 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005861 toggle_dos_compatibility_flag();
5862#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005863 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005864 toggle_sunflags(get_partition(1, partitions),
5865 0x10);
5866#endif
5867#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005868 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005869 sgi_set_swappartition(
5870 get_partition(1, partitions));
5871#endif
5872 else
5873 unknown_command(c);
5874 break;
5875 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005876 {
Eric Andersen040f4402003-07-30 08:40:37 +00005877 int j;
5878#ifdef CONFIG_FEATURE_SGI_LABEL
5879 /* If sgi_label then don't use get_existing_partition,
5880 let the user select a partition, since
5881 get_existing_partition() only works for Linux-like
5882 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005883 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005884 j = get_existing_partition(1, partitions);
5885 } else {
5886 j = get_partition(1, partitions);
5887 }
5888#else
5889 j = get_existing_partition(1, partitions);
5890#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005891 if (j >= 0)
5892 delete_partition(j);
5893 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005894 break;
5895 case 'i':
5896#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005897 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005898 create_sgiinfo();
5899 else
5900#endif
5901 unknown_command(c);
5902 case 'l':
5903 list_types(get_sys_types());
5904 break;
5905 case 'm':
5906 menu();
5907 break;
5908 case 'n':
5909 new_partition();
5910 break;
5911 case 'o':
5912 create_doslabel();
5913 break;
5914 case 'p':
5915 list_table(0);
5916 break;
5917 case 'q':
5918 close(fd);
5919 printf("\n");
5920 return 0;
5921 case 's':
5922#ifdef CONFIG_FEATURE_SUN_LABEL
5923 create_sunlabel();
5924#endif
5925 break;
5926 case 't':
5927 change_sysid();
5928 break;
5929 case 'u':
5930 change_units();
5931 break;
5932 case 'v':
5933 verify();
5934 break;
5935 case 'w':
5936 write_table(); /* does not return */
5937 break;
5938#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5939 case 'x':
5940#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005941 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005942 fprintf(stderr,
5943 _("\n\tSorry, no experts menu for SGI "
5944 "partition tables available.\n\n"));
5945 } else
5946#endif
5947
5948 xselect();
5949 break;
5950#endif
5951 default:
5952 unknown_command(c);
5953 menu();
5954 }
5955 }
5956 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005957#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005958}