blob: 5ef5acb1bb4e1b4c93de4b810bd9cf0f0abe410f [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#define BLKRRPART _IO(0x12,95) /* re-read partition table */
47#define BLKGETSIZE _IO(0x12,96) /* return device size */
48#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
49#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000050
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000051/*
52 fdisk.h
53*/
54
55#define DEFAULT_SECTOR_SIZE 512
56#define MAX_SECTOR_SIZE 2048
57#define SECTOR_SIZE 512 /* still used in BSD code */
58#define MAXIMUM_PARTS 60
59
60#define ACTIVE_FLAG 0x80
61
62#define EXTENDED 0x05
63#define WIN98_EXTENDED 0x0f
64#define LINUX_PARTITION 0x81
65#define LINUX_SWAP 0x82
66#define LINUX_NATIVE 0x83
67#define LINUX_EXTENDED 0x85
68#define LINUX_LVM 0x8e
69#define LINUX_RAID 0xfd
70
71#define SUNOS_SWAP 3
72#define WHOLE_DISK 5
73
74#define IS_EXTENDED(i) \
75 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
76
77#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
78
79#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
80#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
81
Eric Andersen7495b0d2004-02-06 05:26:58 +000082#ifdef CONFIG_FEATURE_SUN_LABEL
83#define SCSI_IOCTL_GET_IDLUN 0x5382
84#endif
85
Eric Andersend3652bf2003-08-06 09:07:37 +000086
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000087/* including <linux/hdreg.h> also fails */
88struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000089 unsigned char heads;
90 unsigned char sectors;
91 unsigned short cylinders;
92 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000093};
94
95#define HDIO_GETGEO 0x0301 /* get device geometry */
96
97
98struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +000099 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000100};
101
Rob Landleyb73451d2006-02-24 16:29:00 +0000102static uint sector_size = DEFAULT_SECTOR_SIZE;
103static uint user_set_sector_size;
104static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000105
106/*
107 * Raw disk label. For DOS-type partition tables the MBR,
108 * with descriptions of the primary partitions.
109 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000110#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000111static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000112#else
113# define MBRbuffer bb_common_bufsiz1
114#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000115
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000116#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000117static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000118#endif
119
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000120static uint heads, sectors, cylinders;
121static void update_units(void);
122
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000123
124/*
125 * return partition name - uses static storage unless buf is supplied
126 */
127static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000128partname(const char *dev, int pno, int lth)
129{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000130 static char buffer[80];
131 const char *p;
132 int w, wp;
133 int bufsiz;
134 char *bufp;
135
136 bufp = buffer;
137 bufsiz = sizeof(buffer);
138
139 w = strlen(dev);
140 p = "";
141
142 if (isdigit(dev[w-1]))
143 p = "p";
144
145 /* devfs kludge - note: fdisk partition names are not supposed
146 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000147 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000148 w -= 4;
149 p = "part";
150 }
151
152 wp = strlen(p);
153
154 if (lth) {
155 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
156 lth-wp-2, w, dev, p, pno);
157 } else {
158 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
159 }
160 return bufp;
161}
162
163struct partition {
164 unsigned char boot_ind; /* 0x80 - active */
165 unsigned char head; /* starting head */
166 unsigned char sector; /* starting sector */
167 unsigned char cyl; /* starting cylinder */
168 unsigned char sys_ind; /* What partition type */
169 unsigned char end_head; /* end head */
170 unsigned char end_sector; /* end sector */
171 unsigned char end_cyl; /* end cylinder */
172 unsigned char start4[4]; /* starting sector counting from 0 */
173 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000174} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000175
176enum failure {
177 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
178 unable_to_write
179};
180
Rob Landley5527b912006-02-25 03:46:10 +0000181enum label_type{
182 label_dos, label_sun, label_sgi, label_aix, label_osf
183};
184
Rob Landleyb73451d2006-02-24 16:29:00 +0000185enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000186
Rob Landley5527b912006-02-25 03:46:10 +0000187static enum label_type current_label_type;
188
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000189static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000190static int fd; /* the disk */
191static int partitions = 4; /* maximum partition + 1 */
192static uint display_in_cyl_units = 1;
193static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000194#ifdef CONFIG_FEATURE_FDISK_WRITABLE
195static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000196static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000197static void reread_partition_table(int leave);
198static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000199static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000200static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000201static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000202#endif
203static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000204static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000205static void get_geometry(void);
206static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000207
208#define PLURAL 0
209#define SINGULAR 1
210
211#define hex_val(c) ({ \
212 char _c = (c); \
213 isdigit(_c) ? _c - '0' : \
214 tolower(_c) + 10 - 'a'; \
215 })
216
217
218#define LINE_LENGTH 800
219#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
220 (n) * sizeof(struct partition)))
221#define sector(s) ((s) & 0x3f)
222#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
223
224#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
225 ((h) + heads * cylinder(s,c)))
226#define set_hsc(h,s,c,sector) { \
227 s = sector % sectors + 1; \
228 sector /= sectors; \
229 h = sector % heads; \
230 sector /= heads; \
231 c = sector & 0xff; \
232 s |= (sector >> 2) & 0xc0; \
233 }
234
235
Eric Andersend9261492004-06-28 23:50:31 +0000236static int32_t get_start_sect(const struct partition *p);
237static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000238
239/*
240 * per partition table entry data
241 *
242 * The four primary partitions have the same sectorbuffer (MBRbuffer)
243 * and have NULL ext_pointer.
244 * Each logical partition table entry has two pointers, one for the
245 * partition and one link to the next one.
246 */
247static struct pte {
248 struct partition *part_table; /* points into sectorbuffer */
249 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000250#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000251 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000252#endif
Eric Andersend9261492004-06-28 23:50:31 +0000253 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000254 char *sectorbuffer; /* disk sector contents */
255} ptes[MAXIMUM_PARTS];
256
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000257
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000258#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000259static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000260set_all_unchanged(void)
261{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000262 int i;
263
264 for (i = 0; i < MAXIMUM_PARTS; i++)
265 ptes[i].changed = 0;
266}
267
268static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000269set_changed(int i)
270{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000271 ptes[i].changed = 1;
272}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000273#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000274
275#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
276static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000277get_part_table(int i)
278{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000279 return ptes[i].part_table;
280}
281#endif
282
283static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000284str_units(int n)
285{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000286 if (n == 1)
287 return display_in_cyl_units ? _("cylinder") : _("sector");
288 else
289 return display_in_cyl_units ? _("cylinders") : _("sectors");
290}
291
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000292static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000293valid_part_table_flag(const char *mbuffer) {
294 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000295 return (b[510] == 0x55 && b[511] == 0xaa);
296}
297
298#ifdef CONFIG_FEATURE_FDISK_WRITABLE
299static char line_buffer[LINE_LENGTH];
300
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000301/* read line; return 0 or first char */
302static int
303read_line(void)
304{
305 static int got_eof = 0;
306
307 fflush (stdout); /* requested by niles@scyld.com */
308 line_ptr = line_buffer;
309 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
310 if (feof(stdin))
311 got_eof++; /* user typed ^D ? */
312 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000313 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
314 exit(1);
315 }
316 return 0;
317 }
318 while (*line_ptr && !isgraph(*line_ptr))
319 line_ptr++;
320 return *line_ptr;
321}
322
323static char
324read_char(const char *mesg)
325{
326 do {
327 fputs(mesg, stdout);
328 } while (!read_line());
329 return *line_ptr;
330}
331
332static char
333read_chars(const char *mesg)
334{
335 fputs(mesg, stdout);
336 if (!read_line()) {
337 *line_ptr = '\n';
338 line_ptr[1] = 0;
339 }
340 return *line_ptr;
341}
342
343static int
344read_hex(const struct systypes *sys)
345{
346 int hex;
347
Rob Landleyb73451d2006-02-24 16:29:00 +0000348 while (1) {
349 read_char(_("Hex code (type L to list codes): "));
350 if (*line_ptr == 'l' || *line_ptr == 'L')
351 list_types(sys);
352 else if (isxdigit (*line_ptr)) {
353 hex = 0;
354 do
355 hex = hex << 4 | hex_val(*line_ptr++);
356 while (isxdigit(*line_ptr));
357 return hex;
358 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000359 }
360}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000361#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000362
363#ifdef CONFIG_FEATURE_AIX_LABEL
364/*
365 * Copyright (C) Andreas Neuper, Sep 1998.
366 * This file may be redistributed under
367 * the terms of the GNU Public License.
368 */
369
370typedef struct {
371 unsigned int magic; /* expect AIX_LABEL_MAGIC */
372 unsigned int fillbytes1[124];
373 unsigned int physical_volume_id;
374 unsigned int fillbytes2[124];
375} aix_partition;
376
377#define AIX_LABEL_MAGIC 0xc9c2d4c1
378#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
379#define AIX_INFO_MAGIC 0x00072959
380#define AIX_INFO_MAGIC_SWAPPED 0x59290700
381
382#define aixlabel ((aix_partition *)MBRbuffer)
383
384
385/*
386 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000387 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
388 * Internationalization
389 *
390 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
391 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000392*/
393
Rob Landleyb73451d2006-02-24 16:29:00 +0000394static int aix_other_endian;
395static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000396
397/*
398 * only dealing with free blocks here
399 */
400
401static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000402aix_info(void)
403{
404 puts(
405 _("\n\tThere is a valid AIX label on this disk.\n"
406 "\tUnfortunately Linux cannot handle these\n"
407 "\tdisks at the moment. Nevertheless some\n"
408 "\tadvice:\n"
409 "\t1. fdisk will destroy its contents on write.\n"
410 "\t2. Be sure that this disk is NOT a still vital\n"
411 "\t part of a volume group. (Otherwise you may\n"
412 "\t erase the other disks as well, if unmirrored.)\n"
413 "\t3. Before deleting this physical volume be sure\n"
414 "\t to remove the disk logically from your AIX\n"
415 "\t machine. (Otherwise you become an AIXpert).")
416 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000417}
418
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000419static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000420check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000421{
Rob Landleyb73451d2006-02-24 16:29:00 +0000422 if (aixlabel->magic != AIX_LABEL_MAGIC &&
423 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000424 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000425 aix_other_endian = 0;
426 return 0;
427 }
428 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
429 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000430 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000431 partitions = 1016;
432 aix_volumes = 15;
433 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000434 /*aix_nolabel();*/ /* %% */
435 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000436 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000437}
438#endif /* AIX_LABEL */
439
440#ifdef CONFIG_FEATURE_OSF_LABEL
441/*
442 * Copyright (c) 1987, 1988 Regents of the University of California.
443 * All rights reserved.
444 *
445 * Redistribution and use in source and binary forms, with or without
446 * modification, are permitted provided that the following conditions
447 * are met:
448 * 1. Redistributions of source code must retain the above copyright
449 * notice, this list of conditions and the following disclaimer.
450 * 2. Redistributions in binary form must reproduce the above copyright
451 * notice, this list of conditions and the following disclaimer in the
452 * documentation and/or other materials provided with the distribution.
453 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000454 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000455 * This product includes software developed by the University of
456 * California, Berkeley and its contributors.
457 * 4. Neither the name of the University nor the names of its contributors
458 * may be used to endorse or promote products derived from this software
459 * without specific prior written permission.
460 *
461 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
462 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
463 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
464 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
465 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
466 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
467 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
468 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
469 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
470 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
471 * SUCH DAMAGE.
472 */
473
474
475#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000476#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000477#endif
478
479#ifndef BSD_MAXPARTITIONS
480#define BSD_MAXPARTITIONS 16
481#endif
482
483#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
484
485#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
486#define BSD_LABELSECTOR 1
487#define BSD_LABELOFFSET 0
488#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
489#define BSD_LABELSECTOR 0
490#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000491#elif defined (__s390__) || defined (__s390x__)
492#define BSD_LABELSECTOR 1
493#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000494#else
495#error unknown architecture
496#endif
497
498#define BSD_BBSIZE 8192 /* size of boot area, with label */
499#define BSD_SBSIZE 8192 /* max size of fs superblock */
500
501struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000502 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000503 int16_t d_type; /* drive type */
504 int16_t d_subtype; /* controller/d_type specific */
505 char d_typename[16]; /* type name, e.g. "eagle" */
506 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000507 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000508 uint32_t d_secsize; /* # of bytes per sector */
509 uint32_t d_nsectors; /* # of data sectors per track */
510 uint32_t d_ntracks; /* # of tracks per cylinder */
511 uint32_t d_ncylinders; /* # of data cylinders per unit */
512 uint32_t d_secpercyl; /* # of data sectors per cylinder */
513 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000514 /*
515 * Spares (bad sector replacements) below
516 * are not counted in d_nsectors or d_secpercyl.
517 * Spare sectors are assumed to be physical sectors
518 * which occupy space at the end of each track and/or cylinder.
519 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000520 uint16_t d_sparespertrack; /* # of spare sectors per track */
521 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000522 /*
523 * Alternate cylinders include maintenance, replacement,
524 * configuration description areas, etc.
525 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000526 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000527
528 /* hardware characteristics: */
529 /*
530 * d_interleave, d_trackskew and d_cylskew describe perturbations
531 * in the media format used to compensate for a slow controller.
532 * Interleave is physical sector interleave, set up by the formatter
533 * or controller when formatting. When interleaving is in use,
534 * logically adjacent sectors are not physically contiguous,
535 * but instead are separated by some number of sectors.
536 * It is specified as the ratio of physical sectors traversed
537 * per logical sector. Thus an interleave of 1:1 implies contiguous
538 * layout, while 2:1 implies that logical sector 0 is separated
539 * by one sector from logical sector 1.
540 * d_trackskew is the offset of sector 0 on track N
541 * relative to sector 0 on track N-1 on the same cylinder.
542 * Finally, d_cylskew is the offset of sector 0 on cylinder N
543 * relative to sector 0 on cylinder N-1.
544 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000545 uint16_t d_rpm; /* rotational speed */
546 uint16_t d_interleave; /* hardware sector interleave */
547 uint16_t d_trackskew; /* sector 0 skew, per track */
548 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
549 uint32_t d_headswitch; /* head switch time, usec */
550 uint32_t d_trkseek; /* track-to-track seek, usec */
551 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000552#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000553 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000554#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000555 uint32_t d_spare[NSPARE]; /* reserved for future use */
556 uint32_t d_magic2; /* the magic number (again) */
557 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000558 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000559 uint16_t d_npartitions; /* number of partitions in following */
560 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
561 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000562 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000563 uint32_t p_size; /* number of sectors in partition */
564 uint32_t p_offset; /* starting sector */
565 uint32_t p_fsize; /* filesystem basic fragment size */
566 uint8_t p_fstype; /* filesystem type, see below */
567 uint8_t p_frag; /* filesystem fragments per block */
568 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000569 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
570};
571
572/* d_type values: */
573#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
574#define BSD_DTYPE_MSCP 2 /* MSCP */
575#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
576#define BSD_DTYPE_SCSI 4 /* SCSI */
577#define BSD_DTYPE_ESDI 5 /* ESDI interface */
578#define BSD_DTYPE_ST506 6 /* ST506 etc. */
579#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
580#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
581#define BSD_DTYPE_FLOPPY 10 /* floppy */
582
583/* d_subtype values: */
584#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
585#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
586#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
587
588#ifdef DKTYPENAMES
589static const char * const xbsd_dktypenames[] = {
590 "unknown",
591 "SMD",
592 "MSCP",
593 "old DEC",
594 "SCSI",
595 "ESDI",
596 "ST506",
597 "HP-IB",
598 "HP-FL",
599 "type 9",
600 "floppy",
601 0
602};
603#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
604#endif
605
606/*
607 * Filesystem type and version.
608 * Used to interpret other filesystem-specific
609 * per-partition information.
610 */
611#define BSD_FS_UNUSED 0 /* unused */
612#define BSD_FS_SWAP 1 /* swap */
613#define BSD_FS_V6 2 /* Sixth Edition */
614#define BSD_FS_V7 3 /* Seventh Edition */
615#define BSD_FS_SYSV 4 /* System V */
616#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
617#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
618#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
619#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
620#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
621#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
622#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
623#define BSD_FS_ISOFS BSD_FS_ISO9660
624#define BSD_FS_BOOT 13 /* partition contains bootstrap */
625#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
626#define BSD_FS_HFS 15 /* Macintosh HFS */
627#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
628
629/* this is annoying, but it's also the way it is :-( */
630#ifdef __alpha__
631#define BSD_FS_EXT2 8 /* ext2 file system */
632#else
633#define BSD_FS_MSDOS 8 /* MS-DOS file system */
634#endif
635
636#ifdef DKTYPENAMES
637static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000638 { "\x00" "unused" }, /* BSD_FS_UNUSED */
639 { "\x01" "swap" }, /* BSD_FS_SWAP */
640 { "\x02" "Version 6" }, /* BSD_FS_V6 */
641 { "\x03" "Version 7" }, /* BSD_FS_V7 */
642 { "\x04" "System V" }, /* BSD_FS_SYSV */
643 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
644 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
645 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000646#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000647 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000648#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000649 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000650#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000651 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
652 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
653 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
654 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
655 { "\x0d" "boot" }, /* BSD_FS_BOOT */
656 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
657 { "\x0f" "HFS" }, /* BSD_FS_HFS */
658 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
659 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000660};
661#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
662
663#endif
664
665/*
666 * flags shared by various drives:
667 */
668#define BSD_D_REMOVABLE 0x01 /* removable media */
669#define BSD_D_ECC 0x02 /* supports ECC */
670#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
671#define BSD_D_RAMDISK 0x08 /* disk emulator */
672#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
673#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
674
675#endif /* OSF_LABEL */
676
677/*
678 * Copyright (C) Andreas Neuper, Sep 1998.
679 * This file may be modified and redistributed under
680 * the terms of the GNU Public License.
681 */
682
683struct device_parameter { /* 48 bytes */
684 unsigned char skew;
685 unsigned char gap1;
686 unsigned char gap2;
687 unsigned char sparecyl;
688 unsigned short pcylcount;
689 unsigned short head_vol0;
690 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
691 unsigned char cmd_tag_queue_depth;
692 unsigned char unused0;
693 unsigned short unused1;
694 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
695 unsigned short bytes;
696 unsigned short ilfact;
697 unsigned int flags; /* controller flags */
698 unsigned int datarate;
699 unsigned int retries_on_error;
700 unsigned int ms_per_word;
701 unsigned short xylogics_gap1;
702 unsigned short xylogics_syncdelay;
703 unsigned short xylogics_readdelay;
704 unsigned short xylogics_gap2;
705 unsigned short xylogics_readgate;
706 unsigned short xylogics_writecont;
707};
708
709#define SGI_VOLHDR 0x00
710/* 1 and 2 were used for drive types no longer supported by SGI */
711#define SGI_SWAP 0x03
712/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
713#define SGI_VOLUME 0x06
714#define SGI_EFS 0x07
715#define SGI_LVOL 0x08
716#define SGI_RLVOL 0x09
717#define SGI_XFS 0x0a
718#define SGI_XFSLOG 0x0b
719#define SGI_XLV 0x0c
720#define SGI_XVM 0x0d
721#define ENTIRE_DISK SGI_VOLUME
722/*
723 * controller flags
724 */
725#define SECTOR_SLIP 0x01
726#define SECTOR_FWD 0x02
727#define TRACK_FWD 0x04
728#define TRACK_MULTIVOL 0x08
729#define IGNORE_ERRORS 0x10
730#define RESEEK 0x20
731#define ENABLE_CMDTAGQ 0x40
732
733typedef struct {
734 unsigned int magic; /* expect SGI_LABEL_MAGIC */
735 unsigned short boot_part; /* active boot partition */
736 unsigned short swap_part; /* active swap partition */
737 unsigned char boot_file[16]; /* name of the bootfile */
738 struct device_parameter devparam; /* 1 * 48 bytes */
739 struct volume_directory { /* 15 * 16 bytes */
740 unsigned char vol_file_name[8]; /* a character array */
741 unsigned int vol_file_start; /* number of logical block */
742 unsigned int vol_file_size; /* number of bytes */
743 } directory[15];
744 struct sgi_partition { /* 16 * 12 bytes */
745 unsigned int num_sectors; /* number of blocks */
746 unsigned int start_sector; /* must be cylinder aligned */
747 unsigned int id;
748 } partitions[16];
749 unsigned int csum;
750 unsigned int fillbytes;
751} sgi_partition;
752
753typedef struct {
754 unsigned int magic; /* looks like a magic number */
755 unsigned int a2;
756 unsigned int a3;
757 unsigned int a4;
758 unsigned int b1;
759 unsigned short b2;
760 unsigned short b3;
761 unsigned int c[16];
762 unsigned short d[3];
763 unsigned char scsi_string[50];
764 unsigned char serial[137];
765 unsigned short check1816;
766 unsigned char installer[225];
767} sgiinfo;
768
769#define SGI_LABEL_MAGIC 0x0be5a941
770#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
771#define SGI_INFO_MAGIC 0x00072959
772#define SGI_INFO_MAGIC_SWAPPED 0x59290700
773#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000774 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000775#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000776 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000777
778#define sgilabel ((sgi_partition *)MBRbuffer)
779#define sgiparam (sgilabel->devparam)
780
781typedef struct {
782 unsigned char info[128]; /* Informative text string */
783 unsigned char spare0[14];
784 struct sun_info {
785 unsigned char spare1;
786 unsigned char id;
787 unsigned char spare2;
788 unsigned char flags;
789 } infos[8];
790 unsigned char spare1[246]; /* Boot information etc. */
791 unsigned short rspeed; /* Disk rotational speed */
792 unsigned short pcylcount; /* Physical cylinder count */
793 unsigned short sparecyl; /* extra sects per cylinder */
794 unsigned char spare2[4]; /* More magic... */
795 unsigned short ilfact; /* Interleave factor */
796 unsigned short ncyl; /* Data cylinder count */
797 unsigned short nacyl; /* Alt. cylinder count */
798 unsigned short ntrks; /* Tracks per cylinder */
799 unsigned short nsect; /* Sectors per track */
800 unsigned char spare3[4]; /* Even more magic... */
801 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000802 uint32_t start_cylinder;
803 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000804 } partitions[8];
805 unsigned short magic; /* Magic number */
806 unsigned short csum; /* Label xor'd checksum */
807} sun_partition;
808
Eric Andersen040f4402003-07-30 08:40:37 +0000809
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000810#define SUN_LABEL_MAGIC 0xDABE
811#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
812#define sunlabel ((sun_partition *)MBRbuffer)
813#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000814 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000815#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000816 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000817
Eric Andersend3652bf2003-08-06 09:07:37 +0000818
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000819#ifdef CONFIG_FEATURE_OSF_LABEL
820/*
821 Changes:
822 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
823
824 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
825 support for OSF/1 disklabels on Alpha.
826 Also fixed unaligned accesses in alpha_bootblock_checksum()
827*/
828
829#define FREEBSD_PARTITION 0xa5
830#define NETBSD_PARTITION 0xa9
831
Rob Landleyb73451d2006-02-24 16:29:00 +0000832static void xbsd_delete_part(void);
833static void xbsd_new_part(void);
834static void xbsd_write_disklabel(void);
835static int xbsd_create_disklabel(void);
836static void xbsd_edit_disklabel(void);
837static void xbsd_write_bootstrap(void);
838static void xbsd_change_fstype(void);
839static int xbsd_get_part_index(int max);
840static int xbsd_check_new_partition(int *i);
841static void xbsd_list_types(void);
842static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
843static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
844static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
845static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000846
847#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000848static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000849#endif
850
851#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000852static int xbsd_translate_fstype(int linux_type);
853static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000854static struct partition *xbsd_part;
855static int xbsd_part_index;
856#endif
857
858#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000859/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000860static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000861#else
862static char disklabelbuffer[BSD_BBSIZE];
863#endif
864
865static struct xbsd_disklabel xbsd_dlabel;
866
867#define bsd_cround(n) \
868 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
869
870/*
871 * Test whether the whole disk has BSD disk label magic.
872 *
873 * Note: often reformatting with DOS-type label leaves the BSD magic,
874 * so this does not mean that there is a BSD disk label.
875 */
876static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000877check_osf_label(void)
878{
879 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000880 return 0;
881 return 1;
882}
883
884static void xbsd_print_disklabel(int);
885
886static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000887btrydev(const char * dev)
888{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000889 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
890 return -1;
891 printf(_("\nBSD label for device: %s\n"), dev);
892 xbsd_print_disklabel (0);
893 return 0;
894}
895
896static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000897bmenu(void)
898{
899 puts (_("Command action"));
900 puts (_("\td\tdelete a BSD partition"));
901 puts (_("\te\tedit drive data"));
902 puts (_("\ti\tinstall bootstrap"));
903 puts (_("\tl\tlist known filesystem types"));
904 puts (_("\tm\tprint this menu"));
905 puts (_("\tn\tadd a new BSD partition"));
906 puts (_("\tp\tprint BSD partition table"));
907 puts (_("\tq\tquit without saving changes"));
908 puts (_("\tr\treturn to main menu"));
909 puts (_("\ts\tshow complete disklabel"));
910 puts (_("\tt\tchange a partition's filesystem id"));
911 puts (_("\tu\tchange units (cylinders/sectors)"));
912 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000913#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000914 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000915#endif
916}
917
918#if !defined (__alpha__)
919static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000920hidden(int type)
921{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000922 return type ^ 0x10;
923}
924
925static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000926is_bsd_partition_type(int type)
927{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000928 return (type == FREEBSD_PARTITION ||
929 type == hidden(FREEBSD_PARTITION) ||
930 type == NETBSD_PARTITION ||
931 type == hidden(NETBSD_PARTITION));
932}
933#endif
934
935static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000936bselect(void)
937{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000938#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000939 int t, ss;
940 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000941
Rob Landleyb73451d2006-02-24 16:29:00 +0000942 for (t = 0; t < 4; t++) {
943 p = get_part_table(t);
944 if (p && is_bsd_partition_type(p->sys_ind)) {
945 xbsd_part = p;
946 xbsd_part_index = t;
947 ss = get_start_sect(xbsd_part);
948 if (ss == 0) {
949 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
950 partname(disk_device, t+1, 0));
951 return;
952 }
953 printf(_("Reading disklabel of %s at sector %d.\n"),
954 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
955 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
956 if (xbsd_create_disklabel() == 0)
957 return;
958 break;
959 }
960 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000961
Rob Landleyb73451d2006-02-24 16:29:00 +0000962 if (t == 4) {
963 printf(_("There is no *BSD partition on %s.\n"), disk_device);
964 return;
965 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000966
967#elif defined (__alpha__)
968
Rob Landleyb73451d2006-02-24 16:29:00 +0000969 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
970 if (xbsd_create_disklabel() == 0)
971 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000972
973#endif
974
Rob Landleyb73451d2006-02-24 16:29:00 +0000975 while (1) {
976 putchar('\n');
977 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
978 case 'd':
979 xbsd_delete_part();
980 break;
981 case 'e':
982 xbsd_edit_disklabel();
983 break;
984 case 'i':
985 xbsd_write_bootstrap();
986 break;
987 case 'l':
988 xbsd_list_types();
989 break;
990 case 'n':
991 xbsd_new_part();
992 break;
993 case 'p':
994 xbsd_print_disklabel(0);
995 break;
996 case 'q':
997 close(fd);
998 exit(EXIT_SUCCESS);
999 case 'r':
1000 return;
1001 case 's':
1002 xbsd_print_disklabel(1);
1003 break;
1004 case 't':
1005 xbsd_change_fstype();
1006 break;
1007 case 'u':
1008 change_units();
1009 break;
1010 case 'w':
1011 xbsd_write_disklabel();
1012 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001013#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001014 case 'x':
1015 xbsd_link_part();
1016 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001017#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001018 default:
1019 bmenu();
1020 break;
1021 }
1022 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001023}
1024
1025static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001026xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001027{
Rob Landleyb73451d2006-02-24 16:29:00 +00001028 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001029
Rob Landleyb73451d2006-02-24 16:29:00 +00001030 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1031 xbsd_dlabel.d_partitions[i].p_size = 0;
1032 xbsd_dlabel.d_partitions[i].p_offset = 0;
1033 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1034 if (xbsd_dlabel.d_npartitions == i + 1)
1035 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1036 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001037}
1038
1039static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001040xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001041{
Rob Landleyb73451d2006-02-24 16:29:00 +00001042 off_t begin, end;
1043 char mesg[256];
1044 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001045
Rob Landleyb73451d2006-02-24 16:29:00 +00001046 if (!xbsd_check_new_partition(&i))
1047 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001048
1049#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001050 begin = get_start_sect(xbsd_part);
1051 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001052#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001053 begin = 0;
1054 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001055#endif
1056
Rob Landleyb73451d2006-02-24 16:29:00 +00001057 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1058 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1059 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001060
Rob Landleyb73451d2006-02-24 16:29:00 +00001061 if (display_in_cyl_units)
1062 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001063
Rob Landleyb73451d2006-02-24 16:29:00 +00001064 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1065 str_units(SINGULAR));
1066 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1067 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001068
Rob Landleyb73451d2006-02-24 16:29:00 +00001069 if (display_in_cyl_units)
1070 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001071
Rob Landleyb73451d2006-02-24 16:29:00 +00001072 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1073 xbsd_dlabel.d_partitions[i].p_offset = begin;
1074 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001075}
1076
1077static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001078xbsd_print_disklabel(int show_all)
1079{
1080 struct xbsd_disklabel *lp = &xbsd_dlabel;
1081 struct xbsd_partition *pp;
1082 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001083
Rob Landleyb73451d2006-02-24 16:29:00 +00001084 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001085#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001086 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001087#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001088 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001089#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001090 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1091 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1092 else
1093 printf(_("type: %d\n"), lp->d_type);
1094 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1095 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1096 printf(_("flags:"));
1097 if (lp->d_flags & BSD_D_REMOVABLE)
1098 printf(_(" removable"));
1099 if (lp->d_flags & BSD_D_ECC)
1100 printf(_(" ecc"));
1101 if (lp->d_flags & BSD_D_BADSECT)
1102 printf(_(" badsect"));
1103 printf("\n");
1104 /* On various machines the fields of *lp are short/int/long */
1105 /* In order to avoid problems, we cast them all to long. */
1106 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1107 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1108 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1109 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1110 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1111 printf(_("rpm: %d\n"), lp->d_rpm);
1112 printf(_("interleave: %d\n"), lp->d_interleave);
1113 printf(_("trackskew: %d\n"), lp->d_trackskew);
1114 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1115 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1116 (long) lp->d_headswitch);
1117 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1118 (long) lp->d_trkseek);
1119 printf(_("drivedata: "));
1120 for (i = NDDATA - 1; i >= 0; i--)
1121 if (lp->d_drivedata[i])
1122 break;
1123 if (i < 0)
1124 i = 0;
1125 for (j = 0; j <= i; j++)
1126 printf("%ld ", (long) lp->d_drivedata[j]);
1127 }
1128 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1129 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1130 pp = lp->d_partitions;
1131 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1132 if (pp->p_size) {
1133 if (display_in_cyl_units && lp->d_secpercyl) {
1134 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1135 'a' + i,
1136 (long) pp->p_offset / lp->d_secpercyl + 1,
1137 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1138 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1139 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1140 (long) pp->p_size / lp->d_secpercyl,
1141 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1142 );
1143 } else {
1144 printf(" %c: %8ld %8ld %8ld ",
1145 'a' + i,
1146 (long) pp->p_offset,
1147 (long) pp->p_offset + pp->p_size - 1,
1148 (long) pp->p_size
1149 );
1150 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001151
Rob Landleyb73451d2006-02-24 16:29:00 +00001152 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1153 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1154 else
1155 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001156
Rob Landleyb73451d2006-02-24 16:29:00 +00001157 switch (pp->p_fstype) {
1158 case BSD_FS_UNUSED:
1159 printf(" %5ld %5ld %5.5s ",
1160 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1161 break;
1162 case BSD_FS_BSDFFS:
1163 printf(" %5ld %5ld %5d ",
1164 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1165 break;
1166 default:
1167 printf("%22.22s", "");
1168 break;
1169 }
1170 printf("\n");
1171 }
1172 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001173}
1174
1175static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001176xbsd_write_disklabel(void)
1177{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001178#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001179 printf(_("Writing disklabel to %s.\n"), disk_device);
1180 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001181#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001182 printf(_("Writing disklabel to %s.\n"),
1183 partname(disk_device, xbsd_part_index + 1, 0));
1184 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001185#endif
1186 reread_partition_table(0); /* no exit yet */
1187}
1188
1189static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001190xbsd_create_disklabel(void)
1191{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001192 char c;
1193
1194#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001195 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001196#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001197 fprintf(stderr, _("%s contains no disklabel.\n"),
1198 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001199#endif
1200
1201 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001202 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001203 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001204 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001205#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001206 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001207 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001208#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001209 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001210#endif
1211 ) == 1) {
1212 xbsd_print_disklabel (1);
1213 return 1;
1214 } else
1215 return 0;
1216 } else if (c == 'n')
1217 return 0;
1218 }
1219}
1220
1221static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001222edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001223{
Rob Landleyb73451d2006-02-24 16:29:00 +00001224 do {
1225 fputs(mesg, stdout);
1226 printf(" (%d): ", def);
1227 if (!read_line())
1228 return def;
1229 }
1230 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1231 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001232}
1233
1234static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001235xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001236{
Rob Landleyb73451d2006-02-24 16:29:00 +00001237 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001238
Rob Landleyb73451d2006-02-24 16:29:00 +00001239 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001240
1241#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001242 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1243 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1244 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1245 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001246#endif
1247
Rob Landleyb73451d2006-02-24 16:29:00 +00001248 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1249 while (1) {
1250 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1251 _("sectors/cylinder"));
1252 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1253 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001254
Rob Landleyb73451d2006-02-24 16:29:00 +00001255 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1256 }
1257 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1258 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1259 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1260 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1261 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1262 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001263
Rob Landleyb73451d2006-02-24 16:29:00 +00001264 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001265}
1266
1267static int
1268xbsd_get_bootstrap (char *path, void *ptr, int size)
1269{
Rob Landleyb73451d2006-02-24 16:29:00 +00001270 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001271
Rob Landleyb73451d2006-02-24 16:29:00 +00001272 if ((fdb = open (path, O_RDONLY)) < 0) {
1273 perror(path);
1274 return 0;
1275 }
1276 if (read(fdb, ptr, size) < 0) {
1277 perror(path);
1278 close(fdb);
1279 return 0;
1280 }
1281 printf(" ... %s\n", path);
1282 close(fdb);
1283 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001284}
1285
1286static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001287sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001288{
Rob Landleyb73451d2006-02-24 16:29:00 +00001289 printf(_("\nSyncing disks.\n"));
1290 sync();
1291 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001292}
1293
1294static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001295xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001296{
Rob Landleyb73451d2006-02-24 16:29:00 +00001297 char *bootdir = BSD_LINUX_BOOTDIR;
1298 char path[MAXPATHLEN];
1299 char *dkbasename;
1300 struct xbsd_disklabel dl;
1301 char *d, *p, *e;
1302 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001303
Rob Landleyb73451d2006-02-24 16:29:00 +00001304 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1305 dkbasename = "sd";
1306 else
1307 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001308
Rob Landleyb73451d2006-02-24 16:29:00 +00001309 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1310 dkbasename, dkbasename, dkbasename);
1311 if (read_line()) {
1312 line_ptr[strlen(line_ptr)-1] = '\0';
1313 dkbasename = line_ptr;
1314 }
1315 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1316 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1317 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001318
Rob Landleyb73451d2006-02-24 16:29:00 +00001319/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1320 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
Mike Frysinger1a540302006-04-16 05:58:21 +00001321 memmove(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001322
Rob Landleyb73451d2006-02-24 16:29:00 +00001323/* The disklabel will be overwritten by 0's from bootxx anyway */
1324 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001325
Rob Landleyb73451d2006-02-24 16:29:00 +00001326 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1327 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001328 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001329 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001330
Rob Landleyb73451d2006-02-24 16:29:00 +00001331 e = d + sizeof(struct xbsd_disklabel);
1332 for (p = d; p < e; p++)
1333 if (*p) {
1334 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1335 exit(EXIT_FAILURE);
1336 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001337
Mike Frysinger1a540302006-04-16 05:58:21 +00001338 memmove(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001339
1340#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001341 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001342#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001343 sector = 0;
1344 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001345#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001346 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001347#endif
1348
Rob Landleyb73451d2006-02-24 16:29:00 +00001349 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1350 fdisk_fatal(unable_to_seek);
1351 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1352 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001353
1354#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001355 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001356#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001357 printf(_("Bootstrap installed on %s.\n"),
1358 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001359#endif
1360
Rob Landleyb73451d2006-02-24 16:29:00 +00001361 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001362}
1363
1364static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001365xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001366{
Rob Landleyb73451d2006-02-24 16:29:00 +00001367 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001368
Rob Landleyb73451d2006-02-24 16:29:00 +00001369 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1370 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001371}
1372
1373static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001374xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001375{
Rob Landleyb73451d2006-02-24 16:29:00 +00001376 char prompt[256];
1377 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001378
Rob Landleyb73451d2006-02-24 16:29:00 +00001379 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1380 do
1381 l = tolower(read_char(prompt));
1382 while (l < 'a' || l > 'a' + max - 1);
1383 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001384}
1385
1386static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001387xbsd_check_new_partition(int *i)
1388{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001389 /* room for more? various BSD flavours have different maxima */
1390 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1391 int t;
1392
1393 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1394 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1395 break;
1396
1397 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001398 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001399 "has been created\n"));
1400 return 0;
1401 }
1402 }
1403
1404 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1405
1406 if (*i >= xbsd_dlabel.d_npartitions)
1407 xbsd_dlabel.d_npartitions = (*i) + 1;
1408
1409 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001410 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001411 return 0;
1412 }
1413
1414 return 1;
1415}
1416
1417static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001418xbsd_list_types(void)
1419{
1420 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001421}
1422
1423static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001424xbsd_dkcksum(struct xbsd_disklabel *lp)
1425{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001426 u_short *start, *end;
1427 u_short sum = 0;
1428
1429 start = (u_short *) lp;
1430 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1431 while (start < end)
1432 sum ^= *start++;
1433 return sum;
1434}
1435
1436static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001437xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1438{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001439 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001440
Rob Landleyb73451d2006-02-24 16:29:00 +00001441 get_geometry();
1442 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001443
Rob Landleyb73451d2006-02-24 16:29:00 +00001444 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001445
Rob Landleyb73451d2006-02-24 16:29:00 +00001446 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1447 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001448 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001449 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001450
1451#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001452 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001453#endif
1454
1455#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001456 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001457#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001458 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001459#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001460 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1461 d->d_nsectors = sectors; /* sectors/track */
1462 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1463 d->d_ncylinders = cylinders;
1464 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1465 if (d->d_secpercyl == 0)
1466 d->d_secpercyl = 1; /* avoid segfaults */
1467 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001468
Rob Landleyb73451d2006-02-24 16:29:00 +00001469 d->d_rpm = 3600;
1470 d->d_interleave = 1;
1471 d->d_trackskew = 0;
1472 d->d_cylskew = 0;
1473 d->d_headswitch = 0;
1474 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001475
Rob Landleyb73451d2006-02-24 16:29:00 +00001476 d->d_magic2 = BSD_DISKMAGIC;
1477 d->d_bbsize = BSD_BBSIZE;
1478 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001479
1480#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001481 d->d_npartitions = 4;
1482 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001483 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001484 pp->p_offset = get_start_sect(p);
1485 pp->p_size = get_nr_sects(p);
1486 pp->p_fstype = BSD_FS_UNUSED;
1487 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001488 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001489 pp->p_offset = 0;
1490 pp->p_size = d->d_secperunit;
1491 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001492#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001493 d->d_npartitions = 3;
1494 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001495 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001496 pp->p_offset = 0;
1497 pp->p_size = d->d_secperunit;
1498 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001499#endif
1500
1501 return 1;
1502}
1503
1504/*
1505 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1506 * If it has the right magic, return 1.
1507 */
1508static int
1509xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1510{
1511 int t, sector;
1512
1513 /* p is used only to get the starting sector */
1514#if !defined (__alpha__)
1515 sector = (p ? get_start_sect(p) : 0);
1516#elif defined (__alpha__)
1517 sector = 0;
1518#endif
1519
Rob Landleyb73451d2006-02-24 16:29:00 +00001520 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1521 fdisk_fatal(unable_to_seek);
1522 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1523 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001524
Mike Frysinger1a540302006-04-16 05:58:21 +00001525 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1526 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001527
Rob Landleyb73451d2006-02-24 16:29:00 +00001528 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001529 return 0;
1530
Rob Landleyb73451d2006-02-24 16:29:00 +00001531 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1532 d->d_partitions[t].p_size = 0;
1533 d->d_partitions[t].p_offset = 0;
1534 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001535 }
1536
Rob Landleyb73451d2006-02-24 16:29:00 +00001537 if (d->d_npartitions > BSD_MAXPARTITIONS)
1538 fprintf(stderr, _("Warning: too many partitions "
1539 "(%d, maximum is %d).\n"),
1540 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001541 return 1;
1542}
1543
1544static int
1545xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1546{
Rob Landleyb73451d2006-02-24 16:29:00 +00001547 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001548
1549#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001550 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001551#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001552 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001553#endif
1554
Rob Landleyb73451d2006-02-24 16:29:00 +00001555 d->d_checksum = 0;
1556 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001557
Rob Landleyb73451d2006-02-24 16:29:00 +00001558 /* This is necessary if we want to write the bootstrap later,
1559 otherwise we'd write the old disklabel with the bootstrap.
1560 */
Mike Frysinger1a540302006-04-16 05:58:21 +00001561 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1562 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001563
1564#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001565 alpha_bootblock_checksum (disklabelbuffer);
1566 if (lseek(fd, 0, SEEK_SET) == -1)
1567 fdisk_fatal(unable_to_seek);
1568 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1569 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001570#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001571 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1572 fdisk_fatal(unable_to_seek);
1573 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1574 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001575#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001576 sync_disks();
1577 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001578}
1579
1580
1581#if !defined (__alpha__)
1582static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001583xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001584{
Rob Landleyb73451d2006-02-24 16:29:00 +00001585 switch (linux_type) {
1586 case 0x01: /* DOS 12-bit FAT */
1587 case 0x04: /* DOS 16-bit <32M */
1588 case 0x06: /* DOS 16-bit >=32M */
1589 case 0xe1: /* DOS access */
1590 case 0xe3: /* DOS R/O */
1591 case 0xf2: /* DOS secondary */
1592 return BSD_FS_MSDOS;
1593 case 0x07: /* OS/2 HPFS */
1594 return BSD_FS_HPFS;
1595 default:
1596 return BSD_FS_OTHER;
1597 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001598}
1599
1600static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001601xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001602{
Rob Landleyb73451d2006-02-24 16:29:00 +00001603 int k, i;
1604 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001605
Rob Landleyb73451d2006-02-24 16:29:00 +00001606 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001607
Rob Landleyb73451d2006-02-24 16:29:00 +00001608 if (!xbsd_check_new_partition(&i))
1609 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001610
Rob Landleyb73451d2006-02-24 16:29:00 +00001611 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001612
Rob Landleyb73451d2006-02-24 16:29:00 +00001613 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1614 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1615 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001616}
1617#endif
1618
1619#if defined (__alpha__)
1620
1621#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001622typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001623#endif
1624
1625static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001626alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001627{
Rob Landleyb73451d2006-02-24 16:29:00 +00001628 uint64_t *dp, sum;
1629 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001630
Rob Landleyb73451d2006-02-24 16:29:00 +00001631 dp = (uint64_t *)boot;
1632 sum = 0;
1633 for (i = 0; i < 63; i++)
1634 sum += dp[i];
1635 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001636}
1637#endif /* __alpha__ */
1638
1639#endif /* OSF_LABEL */
1640
1641#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1642static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001643__swap16(unsigned short x)
1644{
Eric Andersenacd244a2002-12-11 03:49:33 +00001645 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001646}
1647
Eric Andersenacd244a2002-12-11 03:49:33 +00001648static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001649__swap32(uint32_t x)
1650{
1651 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001652 ((x & 0xFF00) << 8) |
1653 ((x & 0xFF0000) >> 8) |
1654 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001655}
1656#endif
1657
1658#ifdef CONFIG_FEATURE_SGI_LABEL
1659/*
1660 *
1661 * fdisksgilabel.c
1662 *
1663 * Copyright (C) Andreas Neuper, Sep 1998.
1664 * This file may be modified and redistributed under
1665 * the terms of the GNU Public License.
1666 *
1667 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1668 * Internationalization
1669 */
1670
1671
Rob Landleyb73451d2006-02-24 16:29:00 +00001672static int sgi_other_endian;
1673static int debug;
1674static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001675
1676/*
1677 * only dealing with free blocks here
1678 */
1679
Rob Landleyb73451d2006-02-24 16:29:00 +00001680typedef struct {
1681 unsigned int first;
1682 unsigned int last;
1683} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001684static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1685
1686static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001687setfreelist(int i, unsigned int f, unsigned int l)
1688{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001689 freelist[i].first = f;
1690 freelist[i].last = l;
1691}
1692
1693static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001694add2freelist(unsigned int f, unsigned int l)
1695{
1696 int i;
1697 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001698 if (freelist[i].last == 0)
1699 break;
1700 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001701}
1702
1703static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001704clearfreelist(void)
1705{
Eric Andersen040f4402003-07-30 08:40:37 +00001706 int i;
1707
1708 for (i = 0; i < 17 ; i++)
1709 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001710}
1711
Eric Andersen040f4402003-07-30 08:40:37 +00001712static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001713isinfreelist(unsigned int b)
1714{
Eric Andersen040f4402003-07-30 08:40:37 +00001715 int i;
1716
1717 for (i = 0; i < 17 ; i++)
1718 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001719 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001720 return 0;
1721}
1722 /* return last vacant block of this stride (never 0). */
1723 /* the '>=' is not quite correct, but simplifies the code */
1724/*
1725 * end of free blocks section
1726 */
1727
1728static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001729/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1730/* 0x01 */ { "\x01" "SGI trkrepl" },
1731/* 0x02 */ { "\x02" "SGI secrepl" },
1732/* SGI_SWAP */ { "\x03" "SGI raw" },
1733/* 0x04 */ { "\x04" "SGI bsd" },
1734/* 0x05 */ { "\x05" "SGI sysv" },
1735/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1736/* SGI_EFS */ { "\x07" "SGI efs" },
1737/* 0x08 */ { "\x08" "SGI lvol" },
1738/* 0x09 */ { "\x09" "SGI rlvol" },
1739/* SGI_XFS */ { "\x0a" "SGI xfs" },
1740/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1741/* SGI_XLV */ { "\x0c" "SGI xlv" },
1742/* SGI_XVM */ { "\x0d" "SGI xvm" },
1743/* LINUX_SWAP */ { "\x82" "Linux swap" },
1744/* LINUX_NATIVE */ { "\x83" "Linux native" },
1745/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1746/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1747 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001748};
1749
1750
1751static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001752sgi_get_nsect(void)
1753{
1754 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001755}
1756
1757static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001758sgi_get_ntrks(void)
1759{
1760 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001761}
1762
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001763static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001764two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1765{
1766 int i = 0;
1767 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001768
Rob Landleyb73451d2006-02-24 16:29:00 +00001769 size /= sizeof(unsigned int);
1770 for (i = 0; i < size; i++)
1771 sum -= SGI_SSWAP32(base[i]);
1772 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001773}
1774
1775static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001776check_sgi_label(void)
1777{
1778 if (sizeof(sgilabel) > 512) {
1779 fprintf(stderr,
1780 _("According to MIPS Computer Systems, Inc the "
1781 "Label must not contain more than 512 bytes\n"));
1782 exit(1);
1783 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001784
Rob Landleyb73451d2006-02-24 16:29:00 +00001785 if (sgilabel->magic != SGI_LABEL_MAGIC
1786 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001787 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001788 return 0;
1789 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001790
Rob Landleyb73451d2006-02-24 16:29:00 +00001791 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1792 /*
1793 * test for correct checksum
1794 */
1795 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1796 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001797 fprintf(stderr,
1798 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001799 }
1800 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001801 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001802 partitions = 16;
1803 sgi_volumes = 15;
1804 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001805}
1806
Eric Andersen040f4402003-07-30 08:40:37 +00001807static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001808sgi_get_start_sector(int i)
1809{
1810 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001811}
1812
Eric Andersen040f4402003-07-30 08:40:37 +00001813static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001814sgi_get_num_sectors(int i)
1815{
1816 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001817}
1818
1819static int
Eric Andersen040f4402003-07-30 08:40:37 +00001820sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001821{
Rob Landleyb73451d2006-02-24 16:29:00 +00001822 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001823}
1824
1825static int
1826sgi_get_bootpartition(void)
1827{
Rob Landleyb73451d2006-02-24 16:29:00 +00001828 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001829}
1830
1831static int
1832sgi_get_swappartition(void)
1833{
Rob Landleyb73451d2006-02-24 16:29:00 +00001834 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001835}
1836
1837static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001838sgi_list_table(int xtra)
1839{
1840 int i, w, wd;
1841 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001842
Rob Landleyb73451d2006-02-24 16:29:00 +00001843 if(xtra) {
1844 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1845 "%d cylinders, %d physical cylinders\n"
1846 "%d extra sects/cyl, interleave %d:1\n"
1847 "%s\n"
1848 "Units = %s of %d * 512 bytes\n\n"),
1849 disk_device, heads, sectors, cylinders,
1850 SGI_SSWAP16(sgiparam.pcylcount),
1851 SGI_SSWAP16(sgiparam.sparecyl),
1852 SGI_SSWAP16(sgiparam.ilfact),
1853 (char *)sgilabel,
1854 str_units(PLURAL), units_per_sector);
1855 } else {
1856 printf( _("\nDisk %s (SGI disk label): "
1857 "%d heads, %d sectors, %d cylinders\n"
1858 "Units = %s of %d * 512 bytes\n\n"),
1859 disk_device, heads, sectors, cylinders,
1860 str_units(PLURAL), units_per_sector );
1861 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001862
Rob Landleyb73451d2006-02-24 16:29:00 +00001863 w = strlen(disk_device);
1864 wd = strlen(_("Device"));
1865 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001866 w = wd;
1867
Rob Landleyb73451d2006-02-24 16:29:00 +00001868 printf(_("----- partitions -----\n"
1869 "Pt# %*s Info Start End Sectors Id System\n"),
1870 w + 2, _("Device"));
1871 for (i = 0 ; i < partitions; i++) {
1872 if( sgi_get_num_sectors(i) || debug ) {
1873 uint32_t start = sgi_get_start_sector(i);
1874 uint32_t len = sgi_get_num_sectors(i);
1875 kpi++; /* only count nonempty partitions */
1876 printf(
1877 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1878/* fdisk part number */ i+1,
1879/* device */ partname(disk_device, kpi, w+3),
1880/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1881/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1882/* start */ (long) scround(start),
1883/* end */ (long) scround(start+len)-1,
1884/* no odd flag on end */(long) len,
1885/* type id */ sgi_get_sysid(i),
1886/* type name */ partition_type(sgi_get_sysid(i)));
1887 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001888 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001889 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1890 "----- Directory Entries -----\n"),
1891 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001892 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001893 if (sgilabel->directory[i].vol_file_size) {
1894 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1895 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1896 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001897
Rob Landleyb73451d2006-02-24 16:29:00 +00001898 printf(_("%2d: %-10s sector%5u size%8u\n"),
1899 i, (char*)name, (unsigned int) start, (unsigned int) len);
1900 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001901 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001902}
1903
1904static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001905sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001906{
Rob Landleyb73451d2006-02-24 16:29:00 +00001907 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001908}
1909
Eric Andersen040f4402003-07-30 08:40:37 +00001910static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001911sgi_get_lastblock(void)
1912{
1913 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001914}
1915
1916static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001917sgi_set_swappartition(int i)
1918{
1919 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001920}
1921
1922static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001923sgi_check_bootfile(const char* aFile)
1924{
1925 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1926 printf(_("\nInvalid Bootfile!\n"
1927 "\tThe bootfile must be an absolute non-zero pathname,\n"
1928 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1929 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001930 } else {
1931 if (strlen(aFile) > 16) {
1932 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001933 "16 bytes maximum.\n"));
1934 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001935 } else {
1936 if (aFile[0] != '/') {
1937 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001938 "fully qualified pathname.\n"));
1939 return 0;
1940 }
Eric Andersen040f4402003-07-30 08:40:37 +00001941 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001942 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001943 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001944 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1945 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001946 /* filename is correct and did change */
1947 return 1;
1948 }
1949 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001950}
1951
1952static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001953sgi_get_bootfile(void)
1954{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001955 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001956}
1957
1958static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001959sgi_set_bootfile(const char* aFile)
1960{
1961 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001962
Rob Landleyb73451d2006-02-24 16:29:00 +00001963 if (sgi_check_bootfile(aFile)) {
1964 while (i < 16) {
1965 if ((aFile[i] != '\n') /* in principle caught again by next line */
1966 && (strlen(aFile) > i))
1967 sgilabel->boot_file[i] = aFile[i];
1968 else
1969 sgilabel->boot_file[i] = 0;
1970 i++;
1971 }
1972 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001973 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001974}
1975
1976static void
1977create_sgiinfo(void)
1978{
Rob Landleyb73451d2006-02-24 16:29:00 +00001979 /* I keep SGI's habit to write the sgilabel to the second block */
1980 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1981 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1982 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001983}
1984
Eric Andersen040f4402003-07-30 08:40:37 +00001985static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001986
1987static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001988sgi_write_table(void)
1989{
1990 sgilabel->csum = 0;
1991 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1992 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1993 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00001994 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00001995
1996 if (lseek(fd, 0, SEEK_SET) < 0)
1997 fdisk_fatal(unable_to_seek);
1998 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1999 fdisk_fatal(unable_to_write);
2000 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2001 /*
2002 * keep this habit of first writing the "sgilabel".
2003 * I never tested whether it works without (AN 981002).
2004 */
2005 sgiinfo *info = fill_sgiinfo();
2006 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2007 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2008 fdisk_fatal(unable_to_seek);
2009 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2010 fdisk_fatal(unable_to_write);
2011 free(info);
2012 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002013}
2014
2015static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002016compare_start(int *x, int *y)
2017{
2018 /*
2019 * sort according to start sectors
2020 * and prefers largest partition:
2021 * entry zero is entire disk entry
2022 */
2023 unsigned int i = *x;
2024 unsigned int j = *y;
2025 unsigned int a = sgi_get_start_sector(i);
2026 unsigned int b = sgi_get_start_sector(j);
2027 unsigned int c = sgi_get_num_sectors(i);
2028 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002029
Rob Landleyb73451d2006-02-24 16:29:00 +00002030 if (a == b)
2031 return (d > c) ? 1 : (d == c) ? 0 : -1;
2032 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002033}
2034
2035
2036static int
Eric Andersen040f4402003-07-30 08:40:37 +00002037verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002038{
Rob Landleyb73451d2006-02-24 16:29:00 +00002039 int Index[16]; /* list of valid partitions */
2040 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2041 int entire = 0, i = 0;
2042 unsigned int start = 0;
2043 long long gap = 0; /* count unused blocks */
2044 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002045
Rob Landleyb73451d2006-02-24 16:29:00 +00002046 clearfreelist();
2047 for (i = 0; i < 16; i++) {
2048 if (sgi_get_num_sectors(i) != 0) {
2049 Index[sortcount++] = i;
2050 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2051 if (entire++ == 1) {
2052 if (verbose)
2053 printf(_("More than one entire disk entry present.\n"));
2054 }
2055 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002056 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002057 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002058 if (sortcount == 0) {
2059 if (verbose)
2060 printf(_("No partitions defined\n"));
2061 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2062 }
2063 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2064 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2065 if ((Index[0] != 10) && verbose)
2066 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2067 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2068 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002069 "at block 0,\n"
2070 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002071 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002072 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002073 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2074 printf(_("The entire disk partition is only %d diskblock large,\n"
2075 "but the disk is %d diskblocks long.\n"),
2076 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002077 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002078 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002079 if (verbose)
2080 printf(_("One Partition (#11) should cover the entire disk.\n"));
2081 if (debug > 2)
2082 printf("sysid=%d\tpartition=%d\n",
2083 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002084 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002085 for (i = 1, start = 0; i < sortcount; i++) {
2086 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2087
2088 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2089 if (debug) /* I do not understand how some disks fulfil it */
2090 if (verbose)
2091 printf(_("Partition %d does not start on cylinder boundary.\n"),
2092 Index[i]+1);
2093 }
2094 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2095 if (debug) /* I do not understand how some disks fulfil it */
2096 if (verbose)
2097 printf(_("Partition %d does not end on cylinder boundary.\n"),
2098 Index[i]+1);
2099 }
2100 /* We cannot handle several "entire disk" entries. */
2101 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2102 if (start > sgi_get_start_sector(Index[i])) {
2103 if (verbose)
2104 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2105 Index[i-1]+1, Index[i]+1,
2106 start - sgi_get_start_sector(Index[i]));
2107 if (gap > 0) gap = -gap;
2108 if (gap == 0) gap = -1;
2109 }
2110 if (start < sgi_get_start_sector(Index[i])) {
2111 if (verbose)
2112 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2113 sgi_get_start_sector(Index[i]) - start,
2114 start, sgi_get_start_sector(Index[i])-1);
2115 gap += sgi_get_start_sector(Index[i]) - start;
2116 add2freelist(start, sgi_get_start_sector(Index[i]));
2117 }
2118 start = sgi_get_start_sector(Index[i])
2119 + sgi_get_num_sectors(Index[i]);
2120 if (debug > 1) {
2121 if (verbose)
2122 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2123 sgi_get_start_sector(Index[i]),
2124 sgi_get_num_sectors(Index[i]),
2125 sgi_get_sysid(Index[i]));
2126 }
2127 }
2128 if (start < lastblock) {
2129 if (verbose)
2130 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2131 lastblock - start, start, lastblock-1);
2132 gap += lastblock - start;
2133 add2freelist(start, lastblock);
2134 }
2135 /*
2136 * Done with arithmetics
2137 * Go for details now
2138 */
2139 if (verbose) {
2140 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2141 printf(_("\nThe boot partition does not exist.\n"));
2142 }
2143 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2144 printf(_("\nThe swap partition does not exist.\n"));
2145 } else {
2146 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2147 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2148 printf(_("\nThe swap partition has no swap type.\n"));
2149 }
2150 if (sgi_check_bootfile("/unix"))
2151 printf(_("\tYou have chosen an unusual boot file name.\n"));
2152 }
2153 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002154}
2155
2156static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002157sgi_gaps(void)
2158{
2159 /*
2160 * returned value is:
2161 * = 0 : disk is properly filled to the rim
2162 * < 0 : there is an overlap
2163 * > 0 : there is still some vacant space
2164 */
2165 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002166}
2167
2168static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002169sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002170{
Rob Landleyb73451d2006-02-24 16:29:00 +00002171 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2172 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2173 return;
2174 }
2175 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2176 && (sgi_get_start_sector(i) < 1) ) {
2177 read_chars(
2178 _("It is highly recommended that the partition at offset 0\n"
2179 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2180 "retrieve from its directory standalone tools like sash and fx.\n"
2181 "Only the \"SGI volume\" entire disk section may violate this.\n"
2182 "Type YES if you are sure about tagging this partition differently.\n"));
2183 if (strcmp(line_ptr, _("YES\n")))
2184 return;
2185 }
2186 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002187}
2188
2189/* returns partition index of first entry marked as entire disk */
2190static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002191sgi_entire(void)
2192{
2193 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002194
Rob Landleyb73451d2006-02-24 16:29:00 +00002195 for (i = 0; i < 16; i++)
2196 if (sgi_get_sysid(i) == SGI_VOLUME)
2197 return i;
2198 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002199}
2200
2201static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002202sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2203{
2204 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2205 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2206 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2207 set_changed(i);
2208 if (sgi_gaps() < 0) /* rebuild freelist */
2209 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002210}
2211
2212static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002213sgi_set_entire(void)
2214{
2215 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002216
Rob Landleyb73451d2006-02-24 16:29:00 +00002217 for (n = 10; n < partitions; n++) {
2218 if(!sgi_get_num_sectors(n) ) {
2219 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2220 break;
2221 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002222 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002223}
2224
2225static void
2226sgi_set_volhdr(void)
2227{
Rob Landleyb73451d2006-02-24 16:29:00 +00002228 int n;
2229
2230 for (n = 8; n < partitions; n++) {
2231 if (!sgi_get_num_sectors(n)) {
2232 /*
2233 * 5 cylinders is an arbitrary value I like
2234 * IRIX 5.3 stored files in the volume header
2235 * (like sash, symmon, fx, ide) with ca. 3200
2236 * sectors.
2237 */
2238 if (heads * sectors * 5 < sgi_get_lastblock())
2239 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2240 break;
2241 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002242 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002243}
2244
2245static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002246sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002247{
Rob Landleyb73451d2006-02-24 16:29:00 +00002248 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002249}
2250
2251static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002252sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002253{
Rob Landleyb73451d2006-02-24 16:29:00 +00002254 char mesg[256];
2255 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002256
Rob Landleyb73451d2006-02-24 16:29:00 +00002257 if (n == 10) {
2258 sys = SGI_VOLUME;
2259 } else if (n == 8) {
2260 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002261 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002262 if(sgi_get_num_sectors(n)) {
2263 printf(_("Partition %d is already defined. Delete "
2264 "it before re-adding it.\n"), n + 1);
2265 return;
2266 }
2267 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2268 printf(_("Attempting to generate entire disk entry automatically.\n"));
2269 sgi_set_entire();
2270 sgi_set_volhdr();
2271 }
2272 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2273 printf(_("The entire disk is already covered with partitions.\n"));
2274 return;
2275 }
2276 if (sgi_gaps() < 0) {
2277 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2278 return;
2279 }
2280 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2281 while (1) {
2282 if(sys == SGI_VOLUME) {
2283 last = sgi_get_lastblock();
2284 first = read_int(0, 0, last-1, 0, mesg);
2285 if (first != 0) {
2286 printf(_("It is highly recommended that eleventh partition\n"
2287 "covers the entire disk and is of type `SGI volume'\n"));
2288 }
2289 } else {
2290 first = freelist[0].first;
2291 last = freelist[0].last;
2292 first = read_int(scround(first), scround(first), scround(last)-1,
2293 0, mesg);
2294 }
2295 if (display_in_cyl_units)
2296 first *= units_per_sector;
2297 else
2298 first = first; /* align to cylinder if you know how ... */
2299 if(!last )
2300 last = isinfreelist(first);
2301 if(last == 0) {
2302 printf(_("You will get a partition overlap on the disk. "
2303 "Fix it first!\n"));
2304 } else
2305 break;
2306 }
2307 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2308 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2309 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002310 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002311 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002312 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002313 last = last; /* align to cylinder if You know how ... */
2314 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2315 printf(_("It is highly recommended that eleventh partition\n"
2316 "covers the entire disk and is of type `SGI volume'\n"));
2317 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002318}
2319
Eric Andersen040f4402003-07-30 08:40:37 +00002320#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002321static void
2322create_sgilabel(void)
2323{
Rob Landleyb73451d2006-02-24 16:29:00 +00002324 struct hd_geometry geometry;
2325 struct {
2326 unsigned int start;
2327 unsigned int nsect;
2328 int sysid;
2329 } old[4];
2330 int i = 0;
2331 long longsectors; /* the number of sectors on the device */
2332 int res; /* the result from the ioctl */
2333 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002334
Rob Landleyb73451d2006-02-24 16:29:00 +00002335 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002336
Rob Landleyb73451d2006-02-24 16:29:00 +00002337 fprintf( stderr,
2338 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2339 "until you decide to write them. After that, of course, the previous\n"
2340 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002341
Rob Landley2c39eee2006-05-05 16:54:40 +00002342 sgi_other_endian = (BB_LITTLE_ENDIAN);
Rob Landleyb73451d2006-02-24 16:29:00 +00002343 res = ioctl(fd, BLKGETSIZE, &longsectors);
2344 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2345 heads = geometry.heads;
2346 sectors = geometry.sectors;
2347 if (res == 0) {
2348 /* the get device size ioctl was successful */
2349 cylinders = longsectors / (heads * sectors);
2350 cylinders /= sec_fac;
2351 } else {
2352 /* otherwise print error and use truncated version */
2353 cylinders = geometry.cylinders;
2354 fprintf(stderr,
2355 _("Warning: BLKGETSIZE ioctl failed on %s. "
2356 "Using geometry cylinder value of %d.\n"
2357 "This value may be truncated for devices"
2358 " > 33.8 GB.\n"), disk_device, cylinders);
2359 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002360 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002361 for (i = 0; i < 4; i++) {
2362 old[i].sysid = 0;
2363 if (valid_part_table_flag(MBRbuffer)) {
2364 if(get_part_table(i)->sys_ind) {
2365 old[i].sysid = get_part_table(i)->sys_ind;
2366 old[i].start = get_start_sect(get_part_table(i));
2367 old[i].nsect = get_nr_sects(get_part_table(i));
2368 printf(_("Trying to keep parameters of partition %d.\n"), i);
2369 if (debug)
2370 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2371 old[i].sysid, old[i].start, old[i].nsect);
2372 }
2373 }
2374 }
Eric Andersen040f4402003-07-30 08:40:37 +00002375
Rob Landleyb73451d2006-02-24 16:29:00 +00002376 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2377 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2378 sgilabel->boot_part = SGI_SSWAP16(0);
2379 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002380
Rob Landleyb73451d2006-02-24 16:29:00 +00002381 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2382 memset(sgilabel->boot_file, 0, 16);
2383 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002384
Rob Landleyb73451d2006-02-24 16:29:00 +00002385 sgilabel->devparam.skew = (0);
2386 sgilabel->devparam.gap1 = (0);
2387 sgilabel->devparam.gap2 = (0);
2388 sgilabel->devparam.sparecyl = (0);
2389 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2390 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2391 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002392 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002393 sgilabel->devparam.cmd_tag_queue_depth = (0);
2394 sgilabel->devparam.unused0 = (0);
2395 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2396 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002397 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002398 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2399 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2400 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002401 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002402 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2403 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2404 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2405 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2406 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2407 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2408 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2409 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2410 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2411 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2412 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002413 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002414 partitions = 16;
2415 sgi_volumes = 15;
2416 sgi_set_entire();
2417 sgi_set_volhdr();
2418 for (i = 0; i < 4; i++) {
2419 if(old[i].sysid) {
2420 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2421 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002422 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002423}
2424
2425static void
2426sgi_set_xcyl(void)
2427{
Rob Landleyb73451d2006-02-24 16:29:00 +00002428 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002429}
Eric Andersen040f4402003-07-30 08:40:37 +00002430#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002431
2432/* _____________________________________________________________
2433 */
2434
Eric Andersen040f4402003-07-30 08:40:37 +00002435static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002436fill_sgiinfo(void)
2437{
Rob Landleyb73451d2006-02-24 16:29:00 +00002438 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002439
Rob Landleyb73451d2006-02-24 16:29:00 +00002440 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2441 info->b1 = SGI_SSWAP32(-1);
2442 info->b2 = SGI_SSWAP16(-1);
2443 info->b3 = SGI_SSWAP16(1);
2444 /* You may want to replace this string !!!!!!! */
2445 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2446 strcpy( (char*)info->serial, "0000" );
2447 info->check1816 = SGI_SSWAP16(18*256 +16 );
2448 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2449 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002450}
2451#endif /* SGI_LABEL */
2452
2453
2454#ifdef CONFIG_FEATURE_SUN_LABEL
2455/*
2456 * fdisksunlabel.c
2457 *
2458 * I think this is mostly, or entirely, due to
2459 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2460 *
2461 * Merged with fdisk for other architectures, aeb, June 1998.
2462 *
2463 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2464 * Internationalization
2465 */
2466
2467
Rob Landleyb73451d2006-02-24 16:29:00 +00002468static int sun_other_endian;
2469static int scsi_disk;
2470static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002471
2472#ifndef IDE0_MAJOR
2473#define IDE0_MAJOR 3
2474#endif
2475#ifndef IDE1_MAJOR
2476#define IDE1_MAJOR 22
2477#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002478
Rob Landleyb73451d2006-02-24 16:29:00 +00002479static void
2480guess_device_type(void)
2481{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002482 struct stat bootstat;
2483
Rob Landleyb73451d2006-02-24 16:29:00 +00002484 if (fstat(fd, &bootstat) < 0) {
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) == IDE0_MAJOR ||
2489 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002490 scsi_disk = 0;
2491 floppy = 0;
2492 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002493 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002494 scsi_disk = 0;
2495 floppy = 1;
2496 } else {
2497 scsi_disk = 1;
2498 floppy = 0;
2499 }
2500}
2501
2502static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002503 { "\x00" "Empty" }, /* 0 */
2504 { "\x01" "Boot" }, /* 1 */
2505 { "\x02" "SunOS root" }, /* 2 */
2506 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2507 { "\x04" "SunOS usr" }, /* 4 */
2508 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2509 { "\x06" "SunOS stand" }, /* 6 */
2510 { "\x07" "SunOS var" }, /* 7 */
2511 { "\x08" "SunOS home" }, /* 8 */
2512 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2513 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2514 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002515/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002516 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2517 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002518};
2519
2520
2521static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002522set_sun_partition(int i, uint start, uint stop, int sysid)
2523{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002524 sunlabel->infos[i].id = sysid;
2525 sunlabel->partitions[i].start_cylinder =
2526 SUN_SSWAP32(start / (heads * sectors));
2527 sunlabel->partitions[i].num_sectors =
2528 SUN_SSWAP32(stop - start);
2529 set_changed(i);
2530}
2531
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002532static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002533check_sun_label(void)
2534{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002535 unsigned short *ush;
2536 int csum;
2537
Rob Landleyb73451d2006-02-24 16:29:00 +00002538 if (sunlabel->magic != SUN_LABEL_MAGIC
2539 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002540 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002541 sun_other_endian = 0;
2542 return 0;
2543 }
2544 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2545 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2546 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2547 if (csum) {
2548 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2549 "Probably you'll have to set all the values,\n"
2550 "e.g. heads, sectors, cylinders and partitions\n"
2551 "or force a fresh label (s command in main menu)\n"));
2552 } else {
2553 heads = SUN_SSWAP16(sunlabel->ntrks);
2554 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2555 sectors = SUN_SSWAP16(sunlabel->nsect);
2556 }
2557 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002558 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002559 partitions = 8;
2560 return 1;
2561}
2562
2563static const struct sun_predefined_drives {
2564 const char *vendor;
2565 const char *model;
2566 unsigned short sparecyl;
2567 unsigned short ncyl;
2568 unsigned short nacyl;
2569 unsigned short pcylcount;
2570 unsigned short ntrks;
2571 unsigned short nsect;
2572 unsigned short rspeed;
2573} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002574 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2575 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2576 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2577 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2578 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2579 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2580 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2581 { "","SUN0104",1,974,2,1019,6,35,3662},
2582 { "","SUN0207",4,1254,2,1272,9,36,3600},
2583 { "","SUN0327",3,1545,2,1549,9,46,3600},
2584 { "","SUN0340",0,1538,2,1544,6,72,4200},
2585 { "","SUN0424",2,1151,2,2500,9,80,4400},
2586 { "","SUN0535",0,1866,2,2500,7,80,5400},
2587 { "","SUN0669",5,1614,2,1632,15,54,3600},
2588 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2589 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2590 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2591 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2592 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002593};
2594
2595static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002596sun_autoconfigure_scsi(void)
2597{
2598 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002599
2600#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002601 unsigned int id[2];
2602 char buffer[2048];
2603 char buffer2[2048];
2604 FILE *pfd;
2605 char *vendor;
2606 char *model;
2607 char *q;
2608 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002609
Rob Landleyb73451d2006-02-24 16:29:00 +00002610 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2611 sprintf(buffer,
2612 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002613#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002614 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002615#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002616 /* This is very wrong (works only if you have one HBA),
2617 but I haven't found a way how to get hostno
2618 from the current kernel */
2619 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002620#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002621 (id[0]>>16) & 0xff,
2622 id[0] & 0xff,
2623 (id[0]>>8) & 0xff
2624 );
2625 pfd = fopen("/proc/scsi/scsi","r");
2626 if (pfd) {
2627 while (fgets(buffer2, 2048, pfd)) {
2628 if (!strcmp(buffer, buffer2)) {
2629 if (fgets(buffer2,2048,pfd)) {
2630 q = strstr(buffer2,"Vendor: ");
2631 if (q) {
2632 q += 8;
2633 vendor = q;
2634 q = strstr(q," ");
2635 *q++ = 0; /* truncate vendor name */
2636 q = strstr(q,"Model: ");
2637 if (q) {
2638 *q = 0;
2639 q += 7;
2640 model = q;
2641 q = strstr(q," Rev: ");
2642 if (q) {
2643 *q = 0;
2644 for (i = 0; i < SIZE(sun_drives); i++) {
2645 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2646 continue;
2647 if (!strstr(model, sun_drives[i].model))
2648 continue;
2649 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2650 p = sun_drives + i;
2651 break;
2652 }
2653 }
2654 }
2655 }
2656 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002657 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002658 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002659 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002660 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002661 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002662 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002663#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002664 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002665}
2666
Rob Landleyb73451d2006-02-24 16:29:00 +00002667static void
2668create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002669{
2670 struct hd_geometry geometry;
2671 unsigned int ndiv;
2672 int i;
2673 unsigned char c;
2674 const struct sun_predefined_drives *p = NULL;
2675
2676 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002677 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2678 "until you decide to write them. After that, of course, the previous\n"
2679 "content won't be recoverable.\n\n"));
Rob Landley2c39eee2006-05-05 16:54:40 +00002680 sun_other_endian = BB_LITTLE_ENDIAN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002681 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2682 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2683 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002684 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002685 " ? auto configure\n"
2686 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002687 for (i = 0; i < SIZE(sun_drives); i++) {
2688 printf(" %c %s%s%s\n",
2689 i + 'a', sun_drives[i].vendor,
2690 (*sun_drives[i].vendor) ? " " : "",
2691 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002692 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002693 while (1) {
2694 c = read_char(_("Select type (? for auto, 0 for custom): "));
2695 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2696 p = sun_drives + c - 'a';
2697 break;
2698 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2699 p = sun_drives + c - 'A';
2700 break;
2701 } else if (c == '0') {
2702 break;
2703 } else if (c == '?' && scsi_disk) {
2704 p = sun_autoconfigure_scsi();
2705 if (!p)
2706 printf(_("Autoconfigure failed.\n"));
2707 else
2708 break;
2709 }
2710 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002711 }
2712 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002713 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2714 heads = geometry.heads;
2715 sectors = geometry.sectors;
2716 cylinders = geometry.cylinders;
2717 } else {
2718 heads = 0;
2719 sectors = 0;
2720 cylinders = 0;
2721 }
2722 if (floppy) {
2723 sunlabel->nacyl = 0;
2724 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2725 sunlabel->rspeed = SUN_SSWAP16(300);
2726 sunlabel->ilfact = SUN_SSWAP16(1);
2727 sunlabel->sparecyl = 0;
2728 } else {
2729 heads = read_int(1,heads,1024,0,_("Heads"));
2730 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002731 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002732 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002733 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002734 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2735 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2736 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2737 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2738 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2739 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2740 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002741 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002742 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2743 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2744 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2745 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2746 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2747 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2748 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2749 sunlabel->ilfact = SUN_SSWAP16(1);
2750 cylinders = p->ncyl;
2751 heads = p->ntrks;
2752 sectors = p->nsect;
2753 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002754 }
2755
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002756 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002757 "%s%s%s cyl %d alt %d hd %d sec %d",
2758 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2759 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002760 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2761
2762 sunlabel->ntrks = SUN_SSWAP16(heads);
2763 sunlabel->nsect = SUN_SSWAP16(sectors);
2764 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2765 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002766 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002767 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002768 if (cylinders * heads * sectors >= 150 * 2048) {
2769 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2770 } else
2771 ndiv = cylinders * 2 / 3;
2772 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2773 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2774 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002775 }
2776 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2777 {
2778 unsigned short *ush = (unsigned short *)sunlabel;
2779 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002780 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002781 csum ^= *ush++;
2782 sunlabel->csum = csum;
2783 }
2784
2785 set_all_unchanged();
2786 set_changed(0);
2787 get_boot(create_empty_sun);
2788}
2789
2790static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002791toggle_sunflags(int i, unsigned char mask)
2792{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002793 if (sunlabel->infos[i].flags & mask)
2794 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002795 else
2796 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002797 set_changed(i);
2798}
2799
2800static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002801fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2802{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002803 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002804
2805 *start = 0;
2806 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002807 for (i = 0; i < partitions; i++) {
2808 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002809 && sunlabel->infos[i].id
2810 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002811 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2812 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2813 if (continuous) {
2814 if (starts[i] == *start)
2815 *start += lens[i];
2816 else if (starts[i] + lens[i] >= *stop)
2817 *stop = starts[i];
2818 else
2819 continuous = 0;
2820 /* There will be probably more gaps
2821 than one, so lets check afterwards */
2822 }
2823 } else {
2824 starts[i] = 0;
2825 lens[i] = 0;
2826 }
2827 }
2828}
2829
2830static uint *verify_sun_starts;
2831
2832static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002833verify_sun_cmp(int *a, int *b)
2834{
2835 if (*a == -1) return 1;
2836 if (*b == -1) return -1;
2837 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2838 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002839}
2840
2841static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002842verify_sun(void)
2843{
2844 uint starts[8], lens[8], start, stop;
2845 int i,j,k,starto,endo;
2846 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002847
Rob Landleyb73451d2006-02-24 16:29:00 +00002848 verify_sun_starts = starts;
2849 fetch_sun(starts,lens,&start,&stop);
2850 for (k = 0; k < 7; k++) {
2851 for (i = 0; i < 8; i++) {
2852 if (k && (lens[i] % (heads * sectors))) {
2853 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002854 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002855 if (lens[i]) {
2856 for (j = 0; j < i; j++)
2857 if (lens[j]) {
2858 if (starts[j] == starts[i]+lens[i]) {
2859 starts[j] = starts[i]; lens[j] += lens[i];
2860 lens[i] = 0;
2861 } else if (starts[i] == starts[j]+lens[j]){
2862 lens[j] += lens[i];
2863 lens[i] = 0;
2864 } else if (!k) {
2865 if (starts[i] < starts[j]+lens[j]
2866 && starts[j] < starts[i]+lens[i]) {
2867 starto = starts[i];
2868 if (starts[j] > starto)
2869 starto = starts[j];
2870 endo = starts[i]+lens[i];
2871 if (starts[j]+lens[j] < endo)
2872 endo = starts[j]+lens[j];
2873 printf(_("Partition %d overlaps with others in "
2874 "sectors %d-%d\n"), i+1, starto, endo);
2875 }
2876 }
2877 }
2878 }
2879 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002880 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002881 for (i = 0; i < 8; i++) {
2882 if (lens[i])
2883 array[i] = i;
2884 else
2885 array[i] = -1;
2886 }
2887 qsort(array,SIZE(array),sizeof(array[0]),
2888 (int (*)(const void *,const void *)) verify_sun_cmp);
2889 if (array[0] == -1) {
2890 printf(_("No partitions defined\n"));
2891 return;
2892 }
2893 stop = cylinders * heads * sectors;
2894 if (starts[array[0]])
2895 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2896 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2897 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2898 }
2899 start = starts[array[i]] + lens[array[i]];
2900 if (start < stop)
2901 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002902}
2903
2904static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002905add_sun_partition(int n, int sys)
2906{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002907 uint start, stop, stop2;
2908 uint starts[8], lens[8];
2909 int whole_disk = 0;
2910
2911 char mesg[256];
2912 int i, first, last;
2913
2914 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2915 printf(_("Partition %d is already defined. Delete "
2916 "it before re-adding it.\n"), n + 1);
2917 return;
2918 }
2919
2920 fetch_sun(starts,lens,&start,&stop);
2921 if (stop <= start) {
2922 if (n == 2)
2923 whole_disk = 1;
2924 else {
2925 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002926 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002927 return;
2928 }
2929 }
2930 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002931 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002932 if (whole_disk)
2933 first = read_int(0, 0, 0, 0, mesg);
2934 else
2935 first = read_int(scround(start), scround(stop)+1,
2936 scround(stop), 0, mesg);
2937 if (display_in_cyl_units)
2938 first *= units_per_sector;
2939 else
2940 /* Starting sector has to be properly aligned */
2941 first = (first + heads * sectors - 1) / (heads * sectors);
2942 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002943 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002944It is highly recommended that the third partition covers the whole disk\n\
2945and is of type `Whole disk'\n");
2946 /* ewt asks to add: "don't start a partition at cyl 0"
2947 However, edmundo@rano.demon.co.uk writes:
2948 "In addition to having a Sun partition table, to be able to
2949 boot from the disc, the first partition, /dev/sdX1, must
2950 start at cylinder 0. This means that /dev/sdX1 contains
2951 the partition table and the boot block, as these are the
2952 first two sectors of the disc. Therefore you must be
2953 careful what you use /dev/sdX1 for. In particular, you must
2954 not use a partition starting at cylinder 0 for Linux swap,
2955 as that would overwrite the partition table and the boot
2956 block. You may, however, use such a partition for a UFS
2957 or EXT2 file system, as these file systems leave the first
2958 1024 bytes undisturbed. */
2959 /* On the other hand, one should not use partitions
2960 starting at block 0 in an md, or the label will
2961 be trashed. */
2962 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002963 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002964 break;
2965 if (i < partitions && !whole_disk) {
2966 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002967 whole_disk = 1;
2968 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002969 }
2970 printf(_("Sector %d is already allocated\n"), first);
2971 } else
2972 break;
2973 }
2974 stop = cylinders * heads * sectors;
2975 stop2 = stop;
2976 for (i = 0; i < partitions; i++) {
2977 if (starts[i] > first && starts[i] < stop)
2978 stop = starts[i];
2979 }
2980 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002981 _("Last %s or +size or +sizeM or +sizeK"),
2982 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002983 if (whole_disk)
2984 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2985 0, mesg);
2986 else if (n == 2 && !first)
2987 last = read_int(scround(first), scround(stop2), scround(stop2),
2988 scround(first), mesg);
2989 else
2990 last = read_int(scround(first), scround(stop), scround(stop),
2991 scround(first), mesg);
2992 if (display_in_cyl_units)
2993 last *= units_per_sector;
2994 if (n == 2 && !first) {
2995 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002996 whole_disk = 1;
2997 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002998 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002999 printf(_("You haven't covered the whole disk with "
3000 "the 3rd partition, but your value\n"
3001 "%d %s covers some other partition. "
3002 "Your entry has been changed\n"
3003 "to %d %s\n"),
3004 scround(last), str_units(SINGULAR),
3005 scround(stop), str_units(SINGULAR));
3006 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003007 }
3008 } else if (!whole_disk && last > stop)
3009 last = stop;
3010
Rob Landleyb73451d2006-02-24 16:29:00 +00003011 if (whole_disk)
3012 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003013 set_sun_partition(n, first, last, sys);
3014}
3015
3016static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003017sun_delete_partition(int i)
3018{
Eric Andersen040f4402003-07-30 08:40:37 +00003019 unsigned int nsec;
3020
Rob Landleyb73451d2006-02-24 16:29:00 +00003021 if (i == 2
3022 && sunlabel->infos[i].id == WHOLE_DISK
3023 && !sunlabel->partitions[i].start_cylinder
3024 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003025 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003026 "consider leaving this\n"
3027 "partition as Whole disk (5), starting at 0, with %u "
3028 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003029 sunlabel->infos[i].id = 0;
3030 sunlabel->partitions[i].num_sectors = 0;
3031}
3032
3033static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003034sun_change_sysid(int i, int sys)
3035{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003036 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003037 read_chars(
3038 _("It is highly recommended that the partition at offset 0\n"
3039 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3040 "there may destroy your partition table and bootblock.\n"
3041 "Type YES if you're very sure you would like that partition\n"
3042 "tagged with 82 (Linux swap): "));
3043 if (strcmp (line_ptr, _("YES\n")))
3044 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003045 }
3046 switch (sys) {
3047 case SUNOS_SWAP:
3048 case LINUX_SWAP:
3049 /* swaps are not mountable by default */
3050 sunlabel->infos[i].flags |= 0x01;
3051 break;
3052 default:
3053 /* assume other types are mountable;
3054 user can change it anyway */
3055 sunlabel->infos[i].flags &= ~0x01;
3056 break;
3057 }
3058 sunlabel->infos[i].id = sys;
3059}
3060
3061static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003062sun_list_table(int xtra)
3063{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003064 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003065
3066 w = strlen(disk_device);
3067 if (xtra)
3068 printf(
3069 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3070 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3071 "%d extra sects/cyl, interleave %d:1\n"
3072 "%s\n"
3073 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003074 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3075 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3076 SUN_SSWAP16(sunlabel->pcylcount),
3077 SUN_SSWAP16(sunlabel->sparecyl),
3078 SUN_SSWAP16(sunlabel->ilfact),
3079 (char *)sunlabel,
3080 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003081 else
3082 printf(
3083 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3084 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003085 disk_device, heads, sectors, cylinders,
3086 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003087
3088 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003089 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003090 for (i = 0 ; i < partitions; i++) {
3091 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003092 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3093 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003094 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3095 partname(disk_device, i+1, w), /* device */
3096 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3097 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3098 (long) scround(start), /* start */
3099 (long) scround(start+len), /* end */
3100 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3101 sunlabel->infos[i].id, /* type id */
3102 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003103 }
3104 }
3105}
3106
Eric Andersen040f4402003-07-30 08:40:37 +00003107#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3108
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003109static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003110sun_set_alt_cyl(void)
3111{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003112 sunlabel->nacyl =
3113 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003114 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003115}
3116
3117static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003118sun_set_ncyl(int cyl)
3119{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003120 sunlabel->ncyl = SUN_SSWAP16(cyl);
3121}
3122
3123static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003124sun_set_xcyl(void)
3125{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003126 sunlabel->sparecyl =
3127 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003128 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003129}
3130
3131static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003132sun_set_ilfact(void)
3133{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003134 sunlabel->ilfact =
3135 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003136 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003137}
3138
3139static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003140sun_set_rspeed(void)
3141{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003142 sunlabel->rspeed =
3143 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003144 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003145}
3146
3147static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003148sun_set_pcylcount(void)
3149{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003150 sunlabel->pcylcount =
3151 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003152 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003153}
Eric Andersen040f4402003-07-30 08:40:37 +00003154#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003155
3156static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003157sun_write_table(void)
3158{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003159 unsigned short *ush = (unsigned short *)sunlabel;
3160 unsigned short csum = 0;
3161
Rob Landleyb73451d2006-02-24 16:29:00 +00003162 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003163 csum ^= *ush++;
3164 sunlabel->csum = csum;
3165 if (lseek(fd, 0, SEEK_SET) < 0)
3166 fdisk_fatal(unable_to_seek);
3167 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3168 fdisk_fatal(unable_to_write);
3169}
3170#endif /* SUN_LABEL */
3171
3172/* DOS partition types */
3173
3174static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003175 { "\x00" "Empty" },
3176 { "\x01" "FAT12" },
3177 { "\x04" "FAT16 <32M" },
3178 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3179 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3180 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3181 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3182 { "\x0b" "Win95 FAT32" },
3183 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3184 { "\x0e" "Win95 FAT16 (LBA)" },
3185 { "\x0f" "Win95 Ext'd (LBA)" },
3186 { "\x11" "Hidden FAT12" },
3187 { "\x12" "Compaq diagnostics" },
3188 { "\x14" "Hidden FAT16 <32M" },
3189 { "\x16" "Hidden FAT16" },
3190 { "\x17" "Hidden HPFS/NTFS" },
3191 { "\x1b" "Hidden Win95 FAT32" },
3192 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3193 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3194 { "\x3c" "PartitionMagic recovery" },
3195 { "\x41" "PPC PReP Boot" },
3196 { "\x42" "SFS" },
3197 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3198 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3199 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3200 { "\x82" "Linux swap" }, /* also Solaris */
3201 { "\x83" "Linux" },
3202 { "\x84" "OS/2 hidden C: drive" },
3203 { "\x85" "Linux extended" },
3204 { "\x86" "NTFS volume set" },
3205 { "\x87" "NTFS volume set" },
3206 { "\x8e" "Linux LVM" },
3207 { "\x9f" "BSD/OS" }, /* BSDI */
3208 { "\xa0" "IBM Thinkpad hibernation" },
3209 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3210 { "\xa6" "OpenBSD" },
3211 { "\xa8" "Darwin UFS" },
3212 { "\xa9" "NetBSD" },
3213 { "\xab" "Darwin boot" },
3214 { "\xb7" "BSDI fs" },
3215 { "\xb8" "BSDI swap" },
3216 { "\xbe" "Solaris boot" },
3217 { "\xeb" "BeOS fs" },
3218 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3219 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3220 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3221 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3222 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3223 autodetect using persistent
3224 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003225#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003226 { "\x02" "XENIX root" },
3227 { "\x03" "XENIX usr" },
3228 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3229 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3230 { "\x10" "OPUS" },
3231 { "\x18" "AST SmartSleep" },
3232 { "\x24" "NEC DOS" },
3233 { "\x39" "Plan 9" },
3234 { "\x40" "Venix 80286" },
3235 { "\x4d" "QNX4.x" },
3236 { "\x4e" "QNX4.x 2nd part" },
3237 { "\x4f" "QNX4.x 3rd part" },
3238 { "\x50" "OnTrack DM" },
3239 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3240 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3241 { "\x53" "OnTrack DM6 Aux3" },
3242 { "\x54" "OnTrackDM6" },
3243 { "\x55" "EZ-Drive" },
3244 { "\x56" "Golden Bow" },
3245 { "\x5c" "Priam Edisk" },
3246 { "\x61" "SpeedStor" },
3247 { "\x64" "Novell Netware 286" },
3248 { "\x65" "Novell Netware 386" },
3249 { "\x70" "DiskSecure Multi-Boot" },
3250 { "\x75" "PC/IX" },
3251 { "\x93" "Amoeba" },
3252 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3253 { "\xa7" "NeXTSTEP" },
3254 { "\xbb" "Boot Wizard hidden" },
3255 { "\xc1" "DRDOS/sec (FAT-12)" },
3256 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3257 { "\xc6" "DRDOS/sec (FAT-16)" },
3258 { "\xc7" "Syrinx" },
3259 { "\xda" "Non-FS data" },
3260 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003261 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003262 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3263 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3264 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003265 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003266 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3267 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003268 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003269 { "\xf1" "SpeedStor" },
3270 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3271 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3272 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003273#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003274 { 0 }
3275};
3276
3277
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003278
3279/* A valid partition table sector ends in 0x55 0xaa */
3280static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003281part_table_flag(const char *b)
3282{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003283 return ((uint) b[510]) + (((uint) b[511]) << 8);
3284}
3285
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003286
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003287#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003288static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003289write_part_table_flag(char *b)
3290{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003291 b[510] = 0x55;
3292 b[511] = 0xaa;
3293}
3294
3295/* start_sect and nr_sects are stored little endian on all machines */
3296/* moreover, they are not aligned correctly */
3297static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003298store4_little_endian(unsigned char *cp, unsigned int val)
3299{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003300 cp[0] = (val & 0xff);
3301 cp[1] = ((val >> 8) & 0xff);
3302 cp[2] = ((val >> 16) & 0xff);
3303 cp[3] = ((val >> 24) & 0xff);
3304}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003305#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003306
3307static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003308read4_little_endian(const unsigned char *cp)
3309{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003310 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3311 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3312}
3313
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003314#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003315static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003316set_start_sect(struct partition *p, unsigned int start_sect)
3317{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003318 store4_little_endian(p->start4, start_sect);
3319}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003320#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003321
Eric Andersend9261492004-06-28 23:50:31 +00003322static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003323get_start_sect(const struct partition *p)
3324{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003325 return read4_little_endian(p->start4);
3326}
3327
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003328#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003329static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003330set_nr_sects(struct partition *p, int32_t nr_sects)
3331{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003332 store4_little_endian(p->size4, nr_sects);
3333}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003334#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003335
Eric Andersend9261492004-06-28 23:50:31 +00003336static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003337get_nr_sects(const struct partition *p)
3338{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003339 return read4_little_endian(p->size4);
3340}
3341
3342/* normally O_RDWR, -l option gives O_RDONLY */
3343static int type_open = O_RDWR;
3344
3345
Rob Landleyb73451d2006-02-24 16:29:00 +00003346static int ext_index; /* the prime extended partition */
3347static int listing; /* no aborts for fdisk -l */
3348static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003349#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3350static int dos_changed;
3351static int nowarn; /* no warnings for fdisk -l/-s */
3352#endif
3353
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003354
3355
Rob Landleyb73451d2006-02-24 16:29:00 +00003356static uint user_cylinders, user_heads, user_sectors;
3357static uint pt_heads, pt_sectors;
3358static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003359
Eric Andersend9261492004-06-28 23:50:31 +00003360static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003361
Eric Andersen040f4402003-07-30 08:40:37 +00003362static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003363
3364
3365static jmp_buf listingbuf;
3366
Rob Landleyb73451d2006-02-24 16:29:00 +00003367static void fdisk_fatal(enum failure why)
3368{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003369 const char *message;
3370
3371 if (listing) {
3372 close(fd);
3373 longjmp(listingbuf, 1);
3374 }
3375
3376 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003377 case unable_to_open:
3378 message = "Unable to open %s\n";
3379 break;
3380 case unable_to_read:
3381 message = "Unable to read %s\n";
3382 break;
3383 case unable_to_seek:
3384 message = "Unable to seek on %s\n";
3385 break;
3386 case unable_to_write:
3387 message = "Unable to write %s\n";
3388 break;
3389 case ioctl_error:
3390 message = "BLKGETSIZE ioctl failed on %s\n";
3391 break;
3392 default:
3393 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003394 }
3395
3396 fputc('\n', stderr);
3397 fprintf(stderr, message, disk_device);
3398 exit(1);
3399}
3400
3401static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003402seek_sector(off_t secno)
3403{
Eric Andersen0a92f352004-03-30 09:21:54 +00003404 off_t offset = secno * sector_size;
3405 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003406 fdisk_fatal(unable_to_seek);
3407}
3408
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003409#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003410static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003411write_sector(off_t secno, char *buf)
3412{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003413 seek_sector(secno);
3414 if (write(fd, buf, sector_size) != sector_size)
3415 fdisk_fatal(unable_to_write);
3416}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003417#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003418
3419/* Allocate a buffer and read a partition table sector */
3420static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003421read_pte(struct pte *pe, off_t offset)
3422{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003423 pe->offset = offset;
3424 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003425 seek_sector(offset);
3426 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3427 fdisk_fatal(unable_to_read);
3428#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003429 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003430#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003431 pe->part_table = pe->ext_pointer = NULL;
3432}
3433
3434static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003435get_partition_start(const struct pte *pe)
3436{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003437 return pe->offset + get_start_sect(pe->part_table);
3438}
3439
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003440#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003441/*
3442 * Avoid warning about DOS partitions when no DOS partition was changed.
3443 * Here a heuristic "is probably dos partition".
3444 * We might also do the opposite and warn in all cases except
3445 * for "is probably nondos partition".
3446 */
3447static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003448is_dos_partition(int t)
3449{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003450 return (t == 1 || t == 4 || t == 6 ||
3451 t == 0x0b || t == 0x0c || t == 0x0e ||
3452 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3453 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3454 t == 0xc1 || t == 0xc4 || t == 0xc6);
3455}
3456
3457static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003458menu(void)
3459{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003460#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003461 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003462 puts(_("Command action"));
3463 puts(_("\ta\ttoggle a read only flag")); /* sun */
3464 puts(_("\tb\tedit bsd disklabel"));
3465 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3466 puts(_("\td\tdelete a partition"));
3467 puts(_("\tl\tlist known partition types"));
3468 puts(_("\tm\tprint this menu"));
3469 puts(_("\tn\tadd a new partition"));
3470 puts(_("\to\tcreate a new empty DOS partition table"));
3471 puts(_("\tp\tprint the partition table"));
3472 puts(_("\tq\tquit without saving changes"));
3473 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3474 puts(_("\tt\tchange a partition's system id"));
3475 puts(_("\tu\tchange display/entry units"));
3476 puts(_("\tv\tverify the partition table"));
3477 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003478#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003479 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003480#endif
3481 } else
3482#endif
3483#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003484 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003485 puts(_("Command action"));
3486 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3487 puts(_("\tb\tedit bootfile entry")); /* sgi */
3488 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3489 puts(_("\td\tdelete a partition"));
3490 puts(_("\tl\tlist known partition types"));
3491 puts(_("\tm\tprint this menu"));
3492 puts(_("\tn\tadd a new partition"));
3493 puts(_("\to\tcreate a new empty DOS partition table"));
3494 puts(_("\tp\tprint the partition table"));
3495 puts(_("\tq\tquit without saving changes"));
3496 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3497 puts(_("\tt\tchange a partition's system id"));
3498 puts(_("\tu\tchange display/entry units"));
3499 puts(_("\tv\tverify the partition table"));
3500 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003501 } else
3502#endif
3503#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003504 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003505 puts(_("Command action"));
3506 puts(_("\tm\tprint this menu"));
3507 puts(_("\to\tcreate a new empty DOS partition table"));
3508 puts(_("\tq\tquit without saving changes"));
3509 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003510 } else
3511#endif
3512 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003513 puts(_("Command action"));
3514 puts(_("\ta\ttoggle a bootable flag"));
3515 puts(_("\tb\tedit bsd disklabel"));
3516 puts(_("\tc\ttoggle the dos compatibility flag"));
3517 puts(_("\td\tdelete a partition"));
3518 puts(_("\tl\tlist known partition types"));
3519 puts(_("\tm\tprint this menu"));
3520 puts(_("\tn\tadd a new partition"));
3521 puts(_("\to\tcreate a new empty DOS partition table"));
3522 puts(_("\tp\tprint the partition table"));
3523 puts(_("\tq\tquit without saving changes"));
3524 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3525 puts(_("\tt\tchange a partition's system id"));
3526 puts(_("\tu\tchange display/entry units"));
3527 puts(_("\tv\tverify the partition table"));
3528 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003529#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003530 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003531#endif
3532 }
3533}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003534#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3535
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003536
3537#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3538static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003539xmenu(void)
3540{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003541#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003542 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003543 puts(_("Command action"));
3544 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3545 puts(_("\tc\tchange number of cylinders"));
3546 puts(_("\td\tprint the raw data in the partition table"));
3547 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3548 puts(_("\th\tchange number of heads"));
3549 puts(_("\ti\tchange interleave factor")); /*sun*/
3550 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3551 puts(_("\tm\tprint this menu"));
3552 puts(_("\tp\tprint the partition table"));
3553 puts(_("\tq\tquit without saving changes"));
3554 puts(_("\tr\treturn to main menu"));
3555 puts(_("\ts\tchange number of sectors/track"));
3556 puts(_("\tv\tverify the partition table"));
3557 puts(_("\tw\twrite table to disk and exit"));
3558 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003559 } else
3560#endif
3561#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003562 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003563 puts(_("Command action"));
3564 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3565 puts(_("\tc\tchange number of cylinders"));
3566 puts(_("\td\tprint the raw data in the partition table"));
3567 puts(_("\te\tlist extended partitions")); /* !sun */
3568 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3569 puts(_("\th\tchange number of heads"));
3570 puts(_("\tm\tprint this menu"));
3571 puts(_("\tp\tprint the partition table"));
3572 puts(_("\tq\tquit without saving changes"));
3573 puts(_("\tr\treturn to main menu"));
3574 puts(_("\ts\tchange number of sectors/track"));
3575 puts(_("\tv\tverify the partition table"));
3576 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003577 } else
3578#endif
3579#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003580 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003581 puts(_("Command action"));
3582 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3583 puts(_("\tc\tchange number of cylinders"));
3584 puts(_("\td\tprint the raw data in the partition table"));
3585 puts(_("\te\tlist extended partitions")); /* !sun */
3586 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3587 puts(_("\th\tchange number of heads"));
3588 puts(_("\tm\tprint this menu"));
3589 puts(_("\tp\tprint the partition table"));
3590 puts(_("\tq\tquit without saving changes"));
3591 puts(_("\tr\treturn to main menu"));
3592 puts(_("\ts\tchange number of sectors/track"));
3593 puts(_("\tv\tverify the partition table"));
3594 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003595 } else
3596#endif
3597 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003598 puts(_("Command action"));
3599 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3600 puts(_("\tc\tchange number of cylinders"));
3601 puts(_("\td\tprint the raw data in the partition table"));
3602 puts(_("\te\tlist extended partitions")); /* !sun */
3603 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003604#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003605 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003606#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003607 puts(_("\th\tchange number of heads"));
3608 puts(_("\tm\tprint this menu"));
3609 puts(_("\tp\tprint the partition table"));
3610 puts(_("\tq\tquit without saving changes"));
3611 puts(_("\tr\treturn to main menu"));
3612 puts(_("\ts\tchange number of sectors/track"));
3613 puts(_("\tv\tverify the partition table"));
3614 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003615 }
3616}
3617#endif /* ADVANCED mode */
3618
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003619#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003620static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003621get_sys_types(void)
3622{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003623 return (
3624#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003625 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003626#endif
3627#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003628 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003629#endif
3630 i386_sys_types);
3631}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003632#else
3633#define get_sys_types() i386_sys_types
3634#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003635
3636static const char *partition_type(unsigned char type)
3637{
3638 int i;
3639 const struct systypes *types = get_sys_types();
3640
Rob Landleyb73451d2006-02-24 16:29:00 +00003641 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003642 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003643 return types[i].name + 1;
3644
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003645 return _("Unknown");
3646}
3647
3648
3649#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3650static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003651get_sysid(int i)
3652{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003653 return (
3654#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003655 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003656#endif
3657#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003658 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003659#endif
3660 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003661}
3662
3663void list_types(const struct systypes *sys)
3664{
3665 uint last[4], done = 0, next = 0, size;
3666 int i;
3667
3668 for (i = 0; sys[i].name; i++);
3669 size = i;
3670
3671 for (i = 3; i >= 0; i--)
3672 last[3 - i] = done += (size + i - done) / (i + 1);
3673 i = done = 0;
3674
3675 do {
3676 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003677 (unsigned char)sys[next].name[0],
3678 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003679 next = last[i++] + done;
3680 if (i > 3 || next >= last[i]) {
3681 i = 0;
3682 next = ++done;
3683 }
3684 } while (done < last[0]);
3685 putchar('\n');
3686}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003687#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003688
3689static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003690is_cleared_partition(const struct partition *p)
3691{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003692 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3693 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3694 get_start_sect(p) || get_nr_sects(p));
3695}
3696
3697static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003698clear_partition(struct partition *p)
3699{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003700 if (!p)
3701 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003702 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003703}
3704
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003705#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003706static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003707set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3708{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003709 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003710 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003711
3712 if (doext) {
3713 p = ptes[i].ext_pointer;
3714 offset = extended_offset;
3715 } else {
3716 p = ptes[i].part_table;
3717 offset = ptes[i].offset;
3718 }
3719 p->boot_ind = 0;
3720 p->sys_ind = sysid;
3721 set_start_sect(p, start - offset);
3722 set_nr_sects(p, stop - start + 1);
3723 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3724 start = heads*sectors*1024 - 1;
3725 set_hsc(p->head, p->sector, p->cyl, start);
3726 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3727 stop = heads*sectors*1024 - 1;
3728 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3729 ptes[i].changed = 1;
3730}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003731#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003732
3733static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003734test_c(const char **m, const char *mesg)
3735{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003736 int val = 0;
3737 if (!*m)
3738 fprintf(stderr, _("You must set"));
3739 else {
3740 fprintf(stderr, " %s", *m);
3741 val = 1;
3742 }
3743 *m = mesg;
3744 return val;
3745}
3746
3747static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003748warn_geometry(void)
3749{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003750 const char *m = NULL;
3751 int prev = 0;
3752
3753 if (!heads)
3754 prev = test_c(&m, _("heads"));
3755 if (!sectors)
3756 prev = test_c(&m, _("sectors"));
3757 if (!cylinders)
3758 prev = test_c(&m, _("cylinders"));
3759 if (!m)
3760 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003761
3762 fprintf(stderr, "%s%s.\n"
3763#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3764 "You can do this from the extra functions menu.\n"
3765#endif
3766 , prev ? _(" and ") : " ", m);
3767
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003768 return 1;
3769}
3770
3771static void update_units(void)
3772{
3773 int cyl_units = heads * sectors;
3774
3775 if (display_in_cyl_units && cyl_units)
3776 units_per_sector = cyl_units;
3777 else
3778 units_per_sector = 1; /* in sectors */
3779}
3780
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003781#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003782static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003783warn_cylinders(void)
3784{
Rob Landley5527b912006-02-25 03:46:10 +00003785 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003786 fprintf(stderr, _("\n"
3787"The number of cylinders for this disk is set to %d.\n"
3788"There is nothing wrong with that, but this is larger than 1024,\n"
3789"and could in certain setups cause problems with:\n"
3790"1) software that runs at boot time (e.g., old versions of LILO)\n"
3791"2) booting and partitioning software from other OSs\n"
3792" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3793 cylinders);
3794}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003795#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003796
3797static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003798read_extended(int ext)
3799{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003800 int i;
3801 struct pte *pex;
3802 struct partition *p, *q;
3803
3804 ext_index = ext;
3805 pex = &ptes[ext];
3806 pex->ext_pointer = pex->part_table;
3807
3808 p = pex->part_table;
3809 if (!get_start_sect(p)) {
3810 fprintf(stderr,
3811 _("Bad offset in primary extended partition\n"));
3812 return;
3813 }
3814
Rob Landleyb73451d2006-02-24 16:29:00 +00003815 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003816 struct pte *pe = &ptes[partitions];
3817
3818 if (partitions >= MAXIMUM_PARTS) {
3819 /* This is not a Linux restriction, but
3820 this program uses arrays of size MAXIMUM_PARTS.
3821 Do not try to `improve' this test. */
3822 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003823#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003824 fprintf(stderr,
3825 _("Warning: deleting partitions after %d\n"),
3826 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003827 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003828#endif
3829 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003830 return;
3831 }
3832
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003833 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003834
3835 if (!extended_offset)
3836 extended_offset = get_start_sect(p);
3837
3838 q = p = pt_offset(pe->sectorbuffer, 0);
3839 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003840 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003841 if (pe->ext_pointer)
3842 fprintf(stderr,
3843 _("Warning: extra link "
3844 "pointer in partition table"
3845 " %d\n"), partitions + 1);
3846 else
3847 pe->ext_pointer = p;
3848 } else if (p->sys_ind) {
3849 if (pe->part_table)
3850 fprintf(stderr,
3851 _("Warning: ignoring extra "
3852 "data in partition table"
3853 " %d\n"), partitions + 1);
3854 else
3855 pe->part_table = p;
3856 }
3857 }
3858
3859 /* very strange code here... */
3860 if (!pe->part_table) {
3861 if (q != pe->ext_pointer)
3862 pe->part_table = q;
3863 else
3864 pe->part_table = q + 1;
3865 }
3866 if (!pe->ext_pointer) {
3867 if (q != pe->part_table)
3868 pe->ext_pointer = q;
3869 else
3870 pe->ext_pointer = q + 1;
3871 }
3872
3873 p = pe->ext_pointer;
3874 partitions++;
3875 }
3876
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003877#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003878 /* remove empty links */
3879 remove:
3880 for (i = 4; i < partitions; i++) {
3881 struct pte *pe = &ptes[i];
3882
3883 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003884 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003885 printf("omitting empty partition (%d)\n", i+1);
3886 delete_partition(i);
3887 goto remove; /* numbering changed */
3888 }
3889 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003890#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003891}
3892
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003893#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003894static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003895create_doslabel(void)
3896{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003897 int i;
3898
3899 fprintf(stderr,
3900 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3901 "until you decide to write them. After that, of course, the previous\n"
3902 "content won't be recoverable.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00003903
3904 current_label_type = label_dos;
3905
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003906#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003907 possibly_osf_label = 0;
3908#endif
3909 partitions = 4;
3910
3911 for (i = 510-64; i < 510; i++)
3912 MBRbuffer[i] = 0;
3913 write_part_table_flag(MBRbuffer);
3914 extended_offset = 0;
3915 set_all_unchanged();
3916 set_changed(0);
3917 get_boot(create_empty_dos);
3918}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003919#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003920
3921static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003922get_sectorsize(void)
3923{
Rob Landley736e5252006-02-25 03:36:00 +00003924 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003925 int arg;
3926 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3927 sector_size = arg;
3928 if (sector_size != DEFAULT_SECTOR_SIZE)
3929 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003930 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003931 }
3932}
3933
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003934static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003935get_kernel_geometry(void)
3936{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003937 struct hd_geometry geometry;
3938
3939 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3940 kern_heads = geometry.heads;
3941 kern_sectors = geometry.sectors;
3942 /* never use geometry.cylinders - it is truncated */
3943 }
3944}
3945
3946static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003947get_partition_table_geometry(void)
3948{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003949 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003950 struct partition *p;
3951 int i, h, s, hh, ss;
3952 int first = 1;
3953 int bad = 0;
3954
Eric Andersen3496fdc2006-01-30 23:09:20 +00003955 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003956 return;
3957
3958 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003959 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003960 p = pt_offset(bufp, i);
3961 if (p->sys_ind != 0) {
3962 h = p->end_head + 1;
3963 s = (p->end_sector & 077);
3964 if (first) {
3965 hh = h;
3966 ss = s;
3967 first = 0;
3968 } else if (hh != h || ss != s)
3969 bad = 1;
3970 }
3971 }
3972
3973 if (!first && !bad) {
3974 pt_heads = hh;
3975 pt_sectors = ss;
3976 }
3977}
3978
Rob Landleyb73451d2006-02-24 16:29:00 +00003979static void
3980get_geometry(void)
3981{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003982 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003983 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003984
3985 get_sectorsize();
3986 sec_fac = sector_size / 512;
3987#ifdef CONFIG_FEATURE_SUN_LABEL
3988 guess_device_type();
3989#endif
3990 heads = cylinders = sectors = 0;
3991 kern_heads = kern_sectors = 0;
3992 pt_heads = pt_sectors = 0;
3993
3994 get_kernel_geometry();
3995 get_partition_table_geometry();
3996
3997 heads = user_heads ? user_heads :
3998 pt_heads ? pt_heads :
3999 kern_heads ? kern_heads : 255;
4000 sectors = user_sectors ? user_sectors :
4001 pt_sectors ? pt_sectors :
4002 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004003 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4004 /* got bytes */
4005 } else {
4006 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004007
4008 if (ioctl(fd, BLKGETSIZE, &longsectors))
4009 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004010 bytes = ((unsigned long long) longsectors) << 9;
4011 }
4012
4013 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004014
4015 sector_offset = 1;
4016 if (dos_compatible_flag)
4017 sector_offset = sectors;
4018
Eric Andersen040f4402003-07-30 08:40:37 +00004019 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004020 if (!cylinders)
4021 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004022}
4023
4024/*
4025 * Read MBR. Returns:
4026 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4027 * 0: found or created label
4028 * 1: I/O error
4029 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004030static int
4031get_boot(enum action what)
4032{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004033 int i;
4034
4035 partitions = 4;
4036
4037 for (i = 0; i < 4; i++) {
4038 struct pte *pe = &ptes[i];
4039
4040 pe->part_table = pt_offset(MBRbuffer, i);
4041 pe->ext_pointer = NULL;
4042 pe->offset = 0;
4043 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004044#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004045 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004046#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004047 }
4048
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004049#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004050 if (what == create_empty_sun && check_sun_label())
4051 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004052#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004053
4054 memset(MBRbuffer, 0, 512);
4055
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004056#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004057 if (what == create_empty_dos)
4058 goto got_dos_table; /* skip reading disk */
4059
4060 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004061 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4062 if (what == try_only)
4063 return 1;
4064 fdisk_fatal(unable_to_open);
4065 } else
4066 printf(_("You will not be able to write "
4067 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004068 }
4069
4070 if (512 != read(fd, MBRbuffer, 512)) {
4071 if (what == try_only)
4072 return 1;
4073 fdisk_fatal(unable_to_read);
4074 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004075#else
4076 if ((fd = open(disk_device, O_RDONLY)) < 0)
4077 return 1;
4078 if (512 != read(fd, MBRbuffer, 512))
4079 return 1;
4080#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004081
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004082 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004083
4084 update_units();
4085
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004086#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004087 if (check_sun_label())
4088 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004089#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004090
4091#ifdef CONFIG_FEATURE_SGI_LABEL
4092 if (check_sgi_label())
4093 return 0;
4094#endif
4095
4096#ifdef CONFIG_FEATURE_AIX_LABEL
4097 if (check_aix_label())
4098 return 0;
4099#endif
4100
4101#ifdef CONFIG_FEATURE_OSF_LABEL
4102 if (check_osf_label()) {
4103 possibly_osf_label = 1;
4104 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004105 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004106 return 0;
4107 }
4108 printf(_("This disk has both DOS and BSD magic.\n"
4109 "Give the 'b' command to go to BSD mode.\n"));
4110 }
4111#endif
4112
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004113#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004114 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004115#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004116
4117 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004118#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4119 return -1;
4120#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004121 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004122 case fdisk:
4123 fprintf(stderr,
4124 _("Device contains neither a valid DOS "
4125 "partition table, nor Sun, SGI or OSF "
4126 "disklabel\n"));
4127#ifdef __sparc__
4128#ifdef CONFIG_FEATURE_SUN_LABEL
4129 create_sunlabel();
4130#endif
4131#else
4132 create_doslabel();
4133#endif
4134 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004135 case try_only:
4136 return -1;
4137 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004138#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004139 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004140#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004141 break;
4142 default:
4143 fprintf(stderr, _("Internal error\n"));
4144 exit(1);
4145 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004146#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004147 }
4148
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004149#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004150 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004151#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004152 warn_geometry();
4153
4154 for (i = 0; i < 4; i++) {
4155 struct pte *pe = &ptes[i];
4156
Rob Landleyb73451d2006-02-24 16:29:00 +00004157 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004158 if (partitions != 4)
4159 fprintf(stderr, _("Ignoring extra extended "
4160 "partition %d\n"), i + 1);
4161 else
4162 read_extended(i);
4163 }
4164 }
4165
4166 for (i = 3; i < partitions; i++) {
4167 struct pte *pe = &ptes[i];
4168
4169 if (!valid_part_table_flag(pe->sectorbuffer)) {
4170 fprintf(stderr,
4171 _("Warning: invalid flag 0x%04x of partition "
4172 "table %d will be corrected by w(rite)\n"),
4173 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004174#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004175 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004176#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004177 }
4178 }
4179
4180 return 0;
4181}
4182
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004183#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004184/*
4185 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4186 * If the user hits Enter, DFLT is returned.
4187 * Answers like +10 are interpreted as offsets from BASE.
4188 *
4189 * There is no default if DFLT is not between LOW and HIGH.
4190 */
4191static uint
4192read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4193{
4194 uint i;
4195 int default_ok = 1;
4196 static char *ms = NULL;
4197 static int mslen = 0;
4198
4199 if (!ms || strlen(mesg)+100 > mslen) {
4200 mslen = strlen(mesg)+200;
4201 ms = xrealloc(ms,mslen);
4202 }
4203
4204 if (dflt < low || dflt > high)
4205 default_ok = 0;
4206
4207 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004208 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004209 mesg, low, high, dflt);
4210 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004211 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004212
4213 while (1) {
4214 int use_default = default_ok;
4215
4216 /* ask question and read answer */
4217 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004218 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004219 continue;
4220
Eric Andersen84bdea82004-05-19 10:49:17 +00004221 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004222 int minus = (*line_ptr == '-');
4223 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004224
Rob Landleyb73451d2006-02-24 16:29:00 +00004225 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004226
Rob Landleyb73451d2006-02-24 16:29:00 +00004227 while (isdigit(*++line_ptr))
4228 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004229
Rob Landleyb73451d2006-02-24 16:29:00 +00004230 switch (*line_ptr) {
4231 case 'c':
4232 case 'C':
4233 if (!display_in_cyl_units)
4234 i *= heads * sectors;
4235 break;
4236 case 'K':
4237 absolute = 1024;
4238 break;
4239 case 'k':
4240 absolute = 1000;
4241 break;
4242 case 'm':
4243 case 'M':
4244 absolute = 1000000;
4245 break;
4246 case 'g':
4247 case 'G':
4248 absolute = 1000000000;
4249 break;
4250 default:
4251 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004252 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004253 if (absolute) {
4254 unsigned long long bytes;
4255 unsigned long unit;
4256
4257 bytes = (unsigned long long) i * absolute;
4258 unit = sector_size * units_per_sector;
4259 bytes += unit/2; /* round */
4260 bytes /= unit;
4261 i = bytes;
4262 }
4263 if (minus)
4264 i = -i;
4265 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004266 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004267 i = atoi(line_ptr);
4268 while (isdigit(*line_ptr)) {
4269 line_ptr++;
4270 use_default = 0;
4271 }
4272 }
4273 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004274 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004275 if (i >= low && i <= high)
4276 break;
4277 else
4278 printf(_("Value out of range.\n"));
4279 }
4280 return i;
4281}
4282
Rob Landleyb73451d2006-02-24 16:29:00 +00004283static int
4284get_partition(int warn, int max)
4285{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004286 struct pte *pe;
4287 int i;
4288
4289 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4290 pe = &ptes[i];
4291
4292 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004293 if (
4294 (
4295 label_sun != current_label_type &&
4296 label_sgi != current_label_type &&
4297 !pe->part_table->sys_ind
4298 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004299#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004300 || (
4301 label_sun == current_label_type &&
4302 (
4303 !sunlabel->partitions[i].num_sectors
4304 || !sunlabel->infos[i].id
4305 )
4306 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004307#endif
4308#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004309 || (
4310 label_sgi == current_label_type &&
4311 !sgi_get_num_sectors(i)
4312 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004313#endif
Rob Landley5527b912006-02-25 03:46:10 +00004314 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004315 fprintf(stderr,
4316 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004317 i+1
4318 );
4319 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004320 }
4321 return i;
4322}
4323
4324static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004325get_existing_partition(int warn, int max)
4326{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004327 int pno = -1;
4328 int i;
4329
4330 for (i = 0; i < max; i++) {
4331 struct pte *pe = &ptes[i];
4332 struct partition *p = pe->part_table;
4333
4334 if (p && !is_cleared_partition(p)) {
4335 if (pno >= 0)
4336 goto not_unique;
4337 pno = i;
4338 }
4339 }
4340 if (pno >= 0) {
4341 printf(_("Selected partition %d\n"), pno+1);
4342 return pno;
4343 }
4344 printf(_("No partition is defined yet!\n"));
4345 return -1;
4346
4347 not_unique:
4348 return get_partition(warn, max);
4349}
4350
4351static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004352get_nonexisting_partition(int warn, int max)
4353{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004354 int pno = -1;
4355 int i;
4356
4357 for (i = 0; i < max; i++) {
4358 struct pte *pe = &ptes[i];
4359 struct partition *p = pe->part_table;
4360
4361 if (p && is_cleared_partition(p)) {
4362 if (pno >= 0)
4363 goto not_unique;
4364 pno = i;
4365 }
4366 }
4367 if (pno >= 0) {
4368 printf(_("Selected partition %d\n"), pno+1);
4369 return pno;
4370 }
4371 printf(_("All primary partitions have been defined already!\n"));
4372 return -1;
4373
4374 not_unique:
4375 return get_partition(warn, max);
4376}
4377
4378
4379void change_units(void)
4380{
4381 display_in_cyl_units = !display_in_cyl_units;
4382 update_units();
4383 printf(_("Changing display/entry units to %s\n"),
4384 str_units(PLURAL));
4385}
4386
4387static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004388toggle_active(int i)
4389{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004390 struct pte *pe = &ptes[i];
4391 struct partition *p = pe->part_table;
4392
Rob Landleyb73451d2006-02-24 16:29:00 +00004393 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004394 fprintf(stderr,
4395 _("WARNING: Partition %d is an extended partition\n"),
4396 i + 1);
4397 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4398 pe->changed = 1;
4399}
4400
4401static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004402toggle_dos_compatibility_flag(void)
4403{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004404 dos_compatible_flag = ~dos_compatible_flag;
4405 if (dos_compatible_flag) {
4406 sector_offset = sectors;
4407 printf(_("DOS Compatibility flag is set\n"));
4408 }
4409 else {
4410 sector_offset = 1;
4411 printf(_("DOS Compatibility flag is not set\n"));
4412 }
4413}
4414
4415static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004416delete_partition(int i)
4417{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004418 struct pte *pe = &ptes[i];
4419 struct partition *p = pe->part_table;
4420 struct partition *q = pe->ext_pointer;
4421
4422/* Note that for the fifth partition (i == 4) we don't actually
4423 * decrement partitions.
4424 */
4425
4426 if (warn_geometry())
4427 return; /* C/H/S not set */
4428 pe->changed = 1;
4429
4430#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004431 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004432 sun_delete_partition(i);
4433 return;
4434 }
4435#endif
4436#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004437 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004438 sgi_delete_partition(i);
4439 return;
4440 }
4441#endif
4442
4443 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004444 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004445 partitions = 4;
4446 ptes[ext_index].ext_pointer = NULL;
4447 extended_offset = 0;
4448 }
4449 clear_partition(p);
4450 return;
4451 }
4452
4453 if (!q->sys_ind && i > 4) {
4454 /* the last one in the chain - just delete */
4455 --partitions;
4456 --i;
4457 clear_partition(ptes[i].ext_pointer);
4458 ptes[i].changed = 1;
4459 } else {
4460 /* not the last one - further ones will be moved down */
4461 if (i > 4) {
4462 /* delete this link in the chain */
4463 p = ptes[i-1].ext_pointer;
4464 *p = *q;
4465 set_start_sect(p, get_start_sect(q));
4466 set_nr_sects(p, get_nr_sects(q));
4467 ptes[i-1].changed = 1;
4468 } else if (partitions > 5) { /* 5 will be moved to 4 */
4469 /* the first logical in a longer chain */
4470 pe = &ptes[5];
4471
4472 if (pe->part_table) /* prevent SEGFAULT */
4473 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004474 get_partition_start(pe) -
4475 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004476 pe->offset = extended_offset;
4477 pe->changed = 1;
4478 }
4479
4480 if (partitions > 5) {
4481 partitions--;
4482 while (i < partitions) {
4483 ptes[i] = ptes[i+1];
4484 i++;
4485 }
4486 } else
4487 /* the only logical: clear only */
4488 clear_partition(ptes[i].part_table);
4489 }
4490}
4491
4492static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004493change_sysid(void)
4494{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004495 int i, sys, origsys;
4496 struct partition *p;
4497
Eric Andersen040f4402003-07-30 08:40:37 +00004498#ifdef CONFIG_FEATURE_SGI_LABEL
4499 /* If sgi_label then don't use get_existing_partition,
4500 let the user select a partition, since get_existing_partition()
4501 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004502 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004503 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004504 } else {
4505 i = get_partition(0, partitions);
4506 }
4507#else
4508 i = get_existing_partition(0, partitions);
4509#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004510 if (i == -1)
4511 return;
4512 p = ptes[i].part_table;
4513 origsys = sys = get_sysid(i);
4514
4515 /* if changing types T to 0 is allowed, then
4516 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004517 if (!sys && label_sgi != current_label_type &&
4518 label_sun != current_label_type && !get_nr_sects(p))
4519 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004520 printf(_("Partition %d does not exist yet!\n"), i + 1);
Rob Landley5527b912006-02-25 03:46:10 +00004521 }else{
4522 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004523 sys = read_hex (get_sys_types());
4524
Rob Landley5527b912006-02-25 03:46:10 +00004525 if (!sys && label_sgi != current_label_type &&
4526 label_sun != current_label_type)
4527 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004528 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004529 "(but not to Linux). Having partitions of\n"
4530 "type 0 is probably unwise. You can delete\n"
4531 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004532 /* break; */
4533 }
4534
Rob Landley5527b912006-02-25 03:46:10 +00004535 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004536 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004537 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004538 " an extended one or vice versa\n"
4539 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004540 break;
4541 }
4542 }
4543
4544 if (sys < 256) {
4545#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004546 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004547 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004548 "as Whole disk (5),\n"
4549 "as SunOS/Solaris expects it and "
4550 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004551#endif
4552#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004553 if (label_sgi == current_label_type &&
4554 (
4555 (i == 10 && sys != ENTIRE_DISK) ||
4556 (i == 8 && sys != 0)
4557 )
4558 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004559 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004560 "as volume header (0),\nand "
4561 "partition 11 as entire volume (6)"
4562 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004563 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004564#endif
4565 if (sys == origsys)
4566 break;
4567#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004568 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004569 sun_change_sysid(i, sys);
4570 } else
4571#endif
4572#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004573 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004574 sgi_change_sysid(i, sys);
4575 } else
4576#endif
4577 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004578
Rob Landleyb73451d2006-02-24 16:29:00 +00004579 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004580 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004581 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004582 ptes[i].changed = 1;
4583 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004584 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004585 dos_changed = 1;
4586 break;
4587 }
Rob Landley5527b912006-02-25 03:46:10 +00004588 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004589 }
4590}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004591#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4592
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004593
4594/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4595 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4596 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4597 * Lubkin Oct. 1991). */
4598
Rob Landleyb73451d2006-02-24 16:29:00 +00004599static void
4600long2chs(ulong ls, uint *c, uint *h, uint *s)
4601{
4602 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004603
4604 *c = ls / spc;
4605 ls = ls % spc;
4606 *h = ls / sectors;
4607 *s = ls % sectors + 1; /* sectors count from 1 */
4608}
4609
Rob Landleyb73451d2006-02-24 16:29:00 +00004610static void
4611check_consistency(const struct partition *p, int partition)
4612{
4613 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4614 uint pec, peh, pes; /* physical ending c, h, s */
4615 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4616 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004617
4618 if (!heads || !sectors || (partition >= 4))
4619 return; /* do not check extended partitions */
4620
4621/* physical beginning c, h, s */
4622 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4623 pbh = p->head;
4624 pbs = p->sector & 0x3f;
4625
4626/* physical ending c, h, s */
4627 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4628 peh = p->end_head;
4629 pes = p->end_sector & 0x3f;
4630
4631/* compute logical beginning (c, h, s) */
4632 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4633
4634/* compute logical ending (c, h, s) */
4635 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4636
4637/* Same physical / logical beginning? */
4638 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4639 printf(_("Partition %d has different physical/logical "
4640 "beginnings (non-Linux?):\n"), partition + 1);
4641 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4642 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4643 }
4644
4645/* Same physical / logical ending? */
4646 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4647 printf(_("Partition %d has different physical/logical "
4648 "endings:\n"), partition + 1);
4649 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4650 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4651 }
4652
4653#if 0
4654/* Beginning on cylinder boundary? */
4655 if (pbh != !pbc || pbs != 1) {
4656 printf(_("Partition %i does not start on cylinder "
4657 "boundary:\n"), partition + 1);
4658 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4659 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4660 }
4661#endif
4662
4663/* Ending on cylinder boundary? */
4664 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004665 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004666 partition + 1);
4667#if 0
4668 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4669 printf(_("should be (%d, %d, %d)\n"),
4670 pec, heads - 1, sectors);
4671#endif
4672 }
4673}
4674
4675static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004676list_disk_geometry(void)
4677{
Eric Andersen040f4402003-07-30 08:40:37 +00004678 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004679 long megabytes = bytes/1000000;
4680
4681 if (megabytes < 10000)
4682 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004683 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004684 else
4685 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004686 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004687 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004688 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004689 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004690 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004691 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004692 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004693 str_units(PLURAL),
4694 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004695}
4696
4697/*
4698 * Check whether partition entries are ordered by their starting positions.
4699 * Return 0 if OK. Return i if partition i should have been earlier.
4700 * Two separate checks: primary and logical partitions.
4701 */
4702static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004703wrong_p_order(int *prev)
4704{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004705 const struct pte *pe;
4706 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004707 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004708 int i, last_i = 0;
4709
4710 for (i = 0 ; i < partitions; i++) {
4711 if (i == 4) {
4712 last_i = 4;
4713 last_p_start_pos = 0;
4714 }
4715 pe = &ptes[i];
4716 if ((p = pe->part_table)->sys_ind) {
4717 p_start_pos = get_partition_start(pe);
4718
4719 if (last_p_start_pos > p_start_pos) {
4720 if (prev)
4721 *prev = last_i;
4722 return i;
4723 }
4724
4725 last_p_start_pos = p_start_pos;
4726 last_i = i;
4727 }
4728 }
4729 return 0;
4730}
4731
4732#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4733/*
4734 * Fix the chain of logicals.
4735 * extended_offset is unchanged, the set of sectors used is unchanged
4736 * The chain is sorted so that sectors increase, and so that
4737 * starting sectors increase.
4738 *
4739 * After this it may still be that cfdisk doesnt like the table.
4740 * (This is because cfdisk considers expanded parts, from link to
4741 * end of partition, and these may still overlap.)
4742 * Now
4743 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4744 * may help.
4745 */
4746static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004747fix_chain_of_logicals(void)
4748{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004749 int j, oj, ojj, sj, sjj;
4750 struct partition *pj,*pjj,tmp;
4751
4752 /* Stage 1: sort sectors but leave sector of part 4 */
4753 /* (Its sector is the global extended_offset.) */
4754 stage1:
4755 for (j = 5; j < partitions-1; j++) {
4756 oj = ptes[j].offset;
4757 ojj = ptes[j+1].offset;
4758 if (oj > ojj) {
4759 ptes[j].offset = ojj;
4760 ptes[j+1].offset = oj;
4761 pj = ptes[j].part_table;
4762 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4763 pjj = ptes[j+1].part_table;
4764 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4765 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004766 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004767 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004768 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004769 goto stage1;
4770 }
4771 }
4772
4773 /* Stage 2: sort starting sectors */
4774 stage2:
4775 for (j = 4; j < partitions-1; j++) {
4776 pj = ptes[j].part_table;
4777 pjj = ptes[j+1].part_table;
4778 sj = get_start_sect(pj);
4779 sjj = get_start_sect(pjj);
4780 oj = ptes[j].offset;
4781 ojj = ptes[j+1].offset;
4782 if (oj+sj > ojj+sjj) {
4783 tmp = *pj;
4784 *pj = *pjj;
4785 *pjj = tmp;
4786 set_start_sect(pj, ojj+sjj-oj);
4787 set_start_sect(pjj, oj+sj-ojj);
4788 goto stage2;
4789 }
4790 }
4791
4792 /* Probably something was changed */
4793 for (j = 4; j < partitions; j++)
4794 ptes[j].changed = 1;
4795}
4796
4797
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004798static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004799fix_partition_table_order(void)
4800{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004801 struct pte *pei, *pek;
4802 int i,k;
4803
4804 if (!wrong_p_order(NULL)) {
4805 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4806 return;
4807 }
4808
4809 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4810 /* partition i should have come earlier, move it */
4811 /* We have to move data in the MBR */
4812 struct partition *pi, *pk, *pe, pbuf;
4813 pei = &ptes[i];
4814 pek = &ptes[k];
4815
4816 pe = pei->ext_pointer;
4817 pei->ext_pointer = pek->ext_pointer;
4818 pek->ext_pointer = pe;
4819
4820 pi = pei->part_table;
4821 pk = pek->part_table;
4822
4823 memmove(&pbuf, pi, sizeof(struct partition));
4824 memmove(pi, pk, sizeof(struct partition));
4825 memmove(pk, &pbuf, sizeof(struct partition));
4826
4827 pei->changed = pek->changed = 1;
4828 }
4829
4830 if (i)
4831 fix_chain_of_logicals();
4832
4833 printf("Done.\n");
4834
4835}
4836#endif
4837
4838static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004839list_table(int xtra)
4840{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004841 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004842 int i, w;
4843
4844#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004845 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004846 sun_list_table(xtra);
4847 return;
4848 }
4849#endif
4850
4851#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004852 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004853 sgi_list_table(xtra);
4854 return;
4855 }
4856#endif
4857
4858 list_disk_geometry();
4859
4860#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004861 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004862 xbsd_print_disklabel(xtra);
4863 return;
4864 }
4865#endif
4866
4867 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4868 but if the device name ends in a digit, say /dev/foo1,
4869 then the partition is called /dev/foo1p3. */
4870 w = strlen(disk_device);
4871 if (w && isdigit(disk_device[w-1]))
4872 w++;
4873 if (w < 5)
4874 w = 5;
4875
4876 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004877 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004878
4879 for (i = 0; i < partitions; i++) {
4880 const struct pte *pe = &ptes[i];
4881
4882 p = pe->part_table;
4883 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004884 off_t psects = get_nr_sects(p);
4885 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004886 unsigned int podd = 0;
4887
4888 if (sector_size < 1024) {
4889 pblocks /= (1024 / sector_size);
4890 podd = psects % (1024 / sector_size);
4891 }
4892 if (sector_size > 1024)
4893 pblocks *= (sector_size / 1024);
4894 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004895 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004896 partname(disk_device, i+1, w+2),
4897/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4898 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004899/* start */ (unsigned long long) cround(get_partition_start(pe)),
4900/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004901 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004902/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004903/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004904/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004905 check_consistency(p, i);
4906 }
4907 }
4908
4909 /* Is partition table in disk order? It need not be, but... */
4910 /* partition table entries are not checked for correct order if this
4911 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004912 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4913 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004914 printf(_("\nPartition table entries are not in disk order\n"));
4915 }
4916}
4917
4918#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4919static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004920x_list_table(int extend)
4921{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004922 const struct pte *pe;
4923 const struct partition *p;
4924 int i;
4925
4926 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4927 disk_device, heads, sectors, cylinders);
4928 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4929 for (i = 0 ; i < partitions; i++) {
4930 pe = &ptes[i];
4931 p = (extend ? pe->ext_pointer : pe->part_table);
4932 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004933 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004934 i + 1, p->boot_ind, p->head,
4935 sector(p->sector),
4936 cylinder(p->sector, p->cyl), p->end_head,
4937 sector(p->end_sector),
4938 cylinder(p->end_sector, p->end_cyl),
4939 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4940 if (p->sys_ind)
4941 check_consistency(p, i);
4942 }
4943 }
4944}
4945#endif
4946
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004947#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004948static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004949fill_bounds(off_t *first, off_t *last)
4950{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004951 int i;
4952 const struct pte *pe = &ptes[0];
4953 const struct partition *p;
4954
4955 for (i = 0; i < partitions; pe++,i++) {
4956 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004957 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004958 first[i] = 0xffffffff;
4959 last[i] = 0;
4960 } else {
4961 first[i] = get_partition_start(pe);
4962 last[i] = first[i] + get_nr_sects(p) - 1;
4963 }
4964 }
4965}
4966
4967static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004968check(int n, uint h, uint s, uint c, off_t start)
4969{
Eric Andersend9261492004-06-28 23:50:31 +00004970 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004971
4972 real_s = sector(s) - 1;
4973 real_c = cylinder(s, c);
4974 total = (real_c * sectors + real_s) * heads + h;
4975 if (!total)
4976 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4977 if (h >= heads)
4978 fprintf(stderr,
4979 _("Partition %d: head %d greater than maximum %d\n"),
4980 n, h + 1, heads);
4981 if (real_s >= sectors)
4982 fprintf(stderr, _("Partition %d: sector %d greater than "
4983 "maximum %d\n"), n, s, sectors);
4984 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004985 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4986 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004987 if (cylinders <= 1024 && start != total)
4988 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004989 _("Partition %d: previous sectors %llu disagrees with "
4990 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004991}
4992
4993static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004994verify(void)
4995{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004996 int i, j;
4997 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00004998 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004999 struct partition *p;
5000
5001 if (warn_geometry())
5002 return;
5003
5004#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005005 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005006 verify_sun();
5007 return;
5008 }
5009#endif
5010#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005011 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005012 verify_sgi(1);
5013 return;
5014 }
5015#endif
5016
5017 fill_bounds(first, last);
5018 for (i = 0; i < partitions; i++) {
5019 struct pte *pe = &ptes[i];
5020
5021 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005022 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005023 check_consistency(p, i);
5024 if (get_partition_start(pe) < first[i])
5025 printf(_("Warning: bad start-of-data in "
5026 "partition %d\n"), i + 1);
5027 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5028 last[i]);
5029 total += last[i] + 1 - first[i];
5030 for (j = 0; j < i; j++)
5031 if ((first[i] >= first[j] && first[i] <= last[j])
5032 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5033 printf(_("Warning: partition %d overlaps "
5034 "partition %d.\n"), j + 1, i + 1);
5035 total += first[i] >= first[j] ?
5036 first[i] : first[j];
5037 total -= last[i] <= last[j] ?
5038 last[i] : last[j];
5039 }
5040 }
5041 }
5042
5043 if (extended_offset) {
5044 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005045 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005046 get_nr_sects(pex->part_table) - 1;
5047
5048 for (i = 4; i < partitions; i++) {
5049 total++;
5050 p = ptes[i].part_table;
5051 if (!p->sys_ind) {
5052 if (i != 4 || i + 1 < partitions)
5053 printf(_("Warning: partition %d "
5054 "is empty\n"), i + 1);
5055 }
5056 else if (first[i] < extended_offset ||
5057 last[i] > e_last)
5058 printf(_("Logical partition %d not entirely in "
5059 "partition %d\n"), i + 1, ext_index + 1);
5060 }
5061 }
5062
5063 if (total > heads * sectors * cylinders)
5064 printf(_("Total allocated sectors %d greater than the maximum "
5065 "%d\n"), total, heads * sectors * cylinders);
5066 else if ((total = heads * sectors * cylinders - total) != 0)
5067 printf(_("%d unallocated sectors\n"), total);
5068}
5069
5070static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005071add_partition(int n, int sys)
5072{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005073 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005074 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005075 struct partition *p = ptes[n].part_table;
5076 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005077 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005078 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005079 first[partitions], last[partitions];
5080
5081 if (p && p->sys_ind) {
5082 printf(_("Partition %d is already defined. Delete "
5083 "it before re-adding it.\n"), n + 1);
5084 return;
5085 }
5086 fill_bounds(first, last);
5087 if (n < 4) {
5088 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005089 if (display_in_cyl_units || !total_number_of_sectors)
5090 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005091 else
Eric Andersen040f4402003-07-30 08:40:37 +00005092 llimit = total_number_of_sectors - 1;
5093 limit = llimit;
5094 if (limit != llimit)
5095 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005096 if (extended_offset) {
5097 first[ext_index] = extended_offset;
5098 last[ext_index] = get_start_sect(q) +
5099 get_nr_sects(q) - 1;
5100 }
5101 } else {
5102 start = extended_offset + sector_offset;
5103 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5104 }
5105 if (display_in_cyl_units)
5106 for (i = 0; i < partitions; i++)
5107 first[i] = (cround(first[i]) - 1) * units_per_sector;
5108
5109 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5110 do {
5111 temp = start;
5112 for (i = 0; i < partitions; i++) {
5113 int lastplusoff;
5114
5115 if (start == ptes[i].offset)
5116 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005117 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005118 if (start >= first[i] && start <= lastplusoff)
5119 start = lastplusoff + 1;
5120 }
5121 if (start > limit)
5122 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005123 if (start >= temp+units_per_sector && num_read) {
Eric Andersend9261492004-06-28 23:50:31 +00005124 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005125 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005126 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005127 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005128 if (!num_read && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005129 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005130
5131 saved_start = start;
5132 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5133 0, mesg);
5134 if (display_in_cyl_units) {
5135 start = (start - 1) * units_per_sector;
5136 if (start < saved_start) start = saved_start;
5137 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005138 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005139 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005140 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005141 if (n > 4) { /* NOT for fifth partition */
5142 struct pte *pe = &ptes[n];
5143
5144 pe->offset = start - sector_offset;
5145 if (pe->offset == extended_offset) { /* must be corrected */
5146 pe->offset++;
5147 if (sector_offset == 1)
5148 start++;
5149 }
5150 }
5151
5152 for (i = 0; i < partitions; i++) {
5153 struct pte *pe = &ptes[i];
5154
5155 if (start < pe->offset && limit >= pe->offset)
5156 limit = pe->offset - 1;
5157 if (start < first[i] && limit >= first[i])
5158 limit = first[i] - 1;
5159 }
5160 if (start > limit) {
5161 printf(_("No free sectors available\n"));
5162 if (n > 4)
5163 partitions--;
5164 return;
5165 }
5166 if (cround(start) == cround(limit)) {
5167 stop = limit;
5168 } else {
5169 snprintf(mesg, sizeof(mesg),
5170 _("Last %s or +size or +sizeM or +sizeK"),
5171 str_units(SINGULAR));
5172 stop = read_int(cround(start), cround(limit), cround(limit),
5173 cround(start), mesg);
5174 if (display_in_cyl_units) {
5175 stop = stop * units_per_sector - 1;
5176 if (stop >limit)
5177 stop = limit;
5178 }
5179 }
5180
5181 set_partition(n, 0, start, stop, sys);
5182 if (n > 4)
5183 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5184
Rob Landleyb73451d2006-02-24 16:29:00 +00005185 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005186 struct pte *pe4 = &ptes[4];
5187 struct pte *pen = &ptes[n];
5188
5189 ext_index = n;
5190 pen->ext_pointer = p;
5191 pe4->offset = extended_offset = start;
5192 pe4->sectorbuffer = xcalloc(1, sector_size);
5193 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5194 pe4->ext_pointer = pe4->part_table + 1;
5195 pe4->changed = 1;
5196 partitions = 5;
5197 }
5198}
5199
5200static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005201add_logical(void)
5202{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005203 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5204 struct pte *pe = &ptes[partitions];
5205
5206 pe->sectorbuffer = xcalloc(1, sector_size);
5207 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5208 pe->ext_pointer = pe->part_table + 1;
5209 pe->offset = 0;
5210 pe->changed = 1;
5211 partitions++;
5212 }
5213 add_partition(partitions - 1, LINUX_NATIVE);
5214}
5215
5216static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005217new_partition(void)
5218{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005219 int i, free_primary = 0;
5220
5221 if (warn_geometry())
5222 return;
5223
5224#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005225 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005226 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5227 return;
5228 }
5229#endif
5230#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005231 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005232 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5233 return;
5234 }
5235#endif
5236#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005237 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005238 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5239 "\n\tIf you want to add DOS-type partitions, create"
5240 "\n\ta new empty DOS partition table first. (Use o.)"
5241 "\n\tWARNING: "
5242 "This will destroy the present disk contents.\n"));
5243 return;
5244 }
5245#endif
5246
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005247 for (i = 0; i < 4; i++)
5248 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005249
Rob Landleyb73451d2006-02-24 16:29:00 +00005250 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005251 printf(_("The maximum number of partitions has been created\n"));
5252 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005253 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005254
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005255 if (!free_primary) {
5256 if (extended_offset)
5257 add_logical();
5258 else
5259 printf(_("You must delete some partition and add "
5260 "an extended partition first\n"));
5261 } else {
5262 char c, line[LINE_LENGTH];
5263 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5264 "partition (1-4)\n",
5265 "Command action", (extended_offset ?
5266 "l logical (5 or over)" : "e extended"));
5267 while (1) {
5268 if ((c = read_char(line)) == 'p' || c == 'P') {
5269 i = get_nonexisting_partition(0, 4);
5270 if (i >= 0)
5271 add_partition(i, LINUX_NATIVE);
5272 return;
5273 }
5274 else if (c == 'l' && extended_offset) {
5275 add_logical();
5276 return;
5277 }
5278 else if (c == 'e' && !extended_offset) {
5279 i = get_nonexisting_partition(0, 4);
5280 if (i >= 0)
5281 add_partition(i, EXTENDED);
5282 return;
5283 }
5284 else
5285 printf(_("Invalid partition number "
5286 "for type `%c'\n"), c);
5287 }
5288 }
5289}
5290
5291static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005292write_table(void)
5293{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005294 int i;
5295
Rob Landley5527b912006-02-25 03:46:10 +00005296 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005297 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005298 if (ptes[i].changed)
5299 ptes[3].changed = 1;
5300 for (i = 3; i < partitions; i++) {
5301 struct pte *pe = &ptes[i];
5302
5303 if (pe->changed) {
5304 write_part_table_flag(pe->sectorbuffer);
5305 write_sector(pe->offset, pe->sectorbuffer);
5306 }
5307 }
5308 }
5309#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005310 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005311 /* no test on change? the printf below might be mistaken */
5312 sgi_write_table();
5313 }
5314#endif
5315#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005316 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005317 int needw = 0;
5318
Rob Landleyb73451d2006-02-24 16:29:00 +00005319 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005320 if (ptes[i].changed)
5321 needw = 1;
5322 if (needw)
5323 sun_write_table();
5324 }
5325#endif
5326
5327 printf(_("The partition table has been altered!\n\n"));
5328 reread_partition_table(1);
5329}
5330
Rob Landleyb73451d2006-02-24 16:29:00 +00005331static void
5332reread_partition_table(int leave)
5333{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005334 int error = 0;
5335 int i;
5336
5337 printf(_("Calling ioctl() to re-read partition table.\n"));
5338 sync();
5339 sleep(2);
5340 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5341 error = errno;
5342 } else {
5343 /* some kernel versions (1.2.x) seem to have trouble
5344 rereading the partition table, but if asked to do it
5345 twice, the second time works. - biro@yggdrasil.com */
5346 sync();
5347 sleep(2);
5348 if ((i = ioctl(fd, BLKRRPART)) != 0)
5349 error = errno;
5350 }
5351
5352 if (i) {
5353 printf(_("\nWARNING: Re-reading the partition table "
5354 "failed with error %d: %s.\n"
5355 "The kernel still uses the old table.\n"
5356 "The new table will be used "
5357 "at the next reboot.\n"),
5358 error, strerror(error));
5359 }
5360
5361 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005362 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005363 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5364 "partitions, please see the fdisk manual page for additional\n"
5365 "information.\n"));
5366
5367 if (leave) {
5368 close(fd);
5369
5370 printf(_("Syncing disks.\n"));
5371 sync();
5372 sleep(4); /* for sync() */
5373 exit(!!i);
5374 }
5375}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005376#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005377
5378#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5379#define MAX_PER_LINE 16
5380static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005381print_buffer(char *pbuffer)
5382{
5383 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005384
5385 for (i = 0, l = 0; i < sector_size; i++, l++) {
5386 if (l == 0)
5387 printf("0x%03X:", i);
5388 printf(" %02X", (unsigned char) pbuffer[i]);
5389 if (l == MAX_PER_LINE - 1) {
5390 printf("\n");
5391 l = -1;
5392 }
5393 }
5394 if (l > 0)
5395 printf("\n");
5396 printf("\n");
5397}
5398
5399
5400static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005401print_raw(void)
5402{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005403 int i;
5404
5405 printf(_("Device: %s\n"), disk_device);
5406#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005407 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005408 print_buffer(MBRbuffer);
5409 else
5410#endif
5411 for (i = 3; i < partitions; i++)
5412 print_buffer(ptes[i].sectorbuffer);
5413}
5414
5415static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005416move_begin(int i)
5417{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005418 struct pte *pe = &ptes[i];
5419 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005420 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005421
5422 if (warn_geometry())
5423 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005424 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005425 printf(_("Partition %d has no data area\n"), i + 1);
5426 return;
5427 }
5428 first = get_partition_start(pe);
5429 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005430 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005431
5432 if (new != get_nr_sects(p)) {
5433 first = get_nr_sects(p) + get_start_sect(p) - new;
5434 set_nr_sects(p, first);
5435 set_start_sect(p, new);
5436 pe->changed = 1;
5437 }
5438}
5439
5440static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005441xselect(void)
5442{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005443 char c;
5444
Rob Landleyb73451d2006-02-24 16:29:00 +00005445 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005446 putchar('\n');
5447 c = tolower(read_char(_("Expert command (m for help): ")));
5448 switch (c) {
5449 case 'a':
5450#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005451 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005452 sun_set_alt_cyl();
5453#endif
5454 break;
5455 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005456 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005457 move_begin(get_partition(0, partitions));
5458 break;
5459 case 'c':
5460 user_cylinders = cylinders =
5461 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005462 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005463#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005464 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005465 sun_set_ncyl(cylinders);
5466#endif
Rob Landley5527b912006-02-25 03:46:10 +00005467 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005468 warn_cylinders();
5469 break;
5470 case 'd':
5471 print_raw();
5472 break;
5473 case 'e':
5474#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005475 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005476 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005477 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005478#endif
5479#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005480 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005481 sun_set_xcyl();
5482 else
5483#endif
Rob Landley5527b912006-02-25 03:46:10 +00005484 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005485 x_list_table(1);
5486 break;
5487 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005488 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005489 fix_partition_table_order();
5490 break;
5491 case 'g':
5492#ifdef CONFIG_FEATURE_SGI_LABEL
5493 create_sgilabel();
5494#endif
5495 break;
5496 case 'h':
5497 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005498 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005499 update_units();
5500 break;
5501 case 'i':
5502#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005503 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005504 sun_set_ilfact();
5505#endif
5506 break;
5507 case 'o':
5508#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005509 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005510 sun_set_rspeed();
5511#endif
5512 break;
5513 case 'p':
5514#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005515 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005516 list_table(1);
5517 else
5518#endif
5519 x_list_table(0);
5520 break;
5521 case 'q':
5522 close(fd);
5523 printf("\n");
5524 exit(0);
5525 case 'r':
5526 return;
5527 case 's':
5528 user_sectors = sectors = read_int(1, sectors, 63, 0,
5529 _("Number of sectors"));
5530 if (dos_compatible_flag) {
5531 sector_offset = sectors;
5532 fprintf(stderr, _("Warning: setting "
5533 "sector offset for DOS "
5534 "compatiblity\n"));
5535 }
5536 update_units();
5537 break;
5538 case 'v':
5539 verify();
5540 break;
5541 case 'w':
5542 write_table(); /* does not return */
5543 break;
5544 case 'y':
5545#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005546 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005547 sun_set_pcylcount();
5548#endif
5549 break;
5550 default:
5551 xmenu();
5552 }
5553 }
5554}
5555#endif /* ADVANCED mode */
5556
5557static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005558is_ide_cdrom_or_tape(const char *device)
5559{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005560 FILE *procf;
5561 char buf[100];
5562 struct stat statbuf;
5563 int is_ide = 0;
5564
5565 /* No device was given explicitly, and we are trying some
5566 likely things. But opening /dev/hdc may produce errors like
5567 "hdc: tray open or drive not ready"
5568 if it happens to be a CD-ROM drive. It even happens that
5569 the process hangs on the attempt to read a music CD.
5570 So try to be careful. This only works since 2.1.73. */
5571
5572 if (strncmp("/dev/hd", device, 7))
5573 return 0;
5574
5575 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5576 procf = fopen(buf, "r");
5577 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5578 is_ide = (!strncmp(buf, "cdrom", 5) ||
5579 !strncmp(buf, "tape", 4));
5580 else
5581 /* Now when this proc file does not exist, skip the
5582 device when it is read-only. */
5583 if (stat(device, &statbuf) == 0)
5584 is_ide = ((statbuf.st_mode & 0222) == 0);
5585
5586 if (procf)
5587 fclose(procf);
5588 return is_ide;
5589}
5590
Rob Landley5527b912006-02-25 03:46:10 +00005591
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005592static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005593try(const char *device, int user_specified)
5594{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005595 int gb;
5596
5597 disk_device = device;
5598 if (setjmp(listingbuf))
5599 return;
5600 if (!user_specified)
5601 if (is_ide_cdrom_or_tape(device))
5602 return;
5603 if ((fd = open(disk_device, type_open)) >= 0) {
5604 gb = get_boot(try_only);
5605 if (gb > 0) { /* I/O error */
5606 close(fd);
5607 } else if (gb < 0) { /* no DOS signature */
5608 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005609 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005610 return;
Rob Landley5527b912006-02-25 03:46:10 +00005611 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005612#ifdef CONFIG_FEATURE_OSF_LABEL
5613 if (btrydev(device) < 0)
5614#endif
5615 fprintf(stderr,
5616 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005617 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005618 close(fd);
5619 } else {
5620 close(fd);
5621 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005622#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005623 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005624 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005625 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005626#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005627 }
5628 } else {
5629 /* Ignore other errors, since we try IDE
5630 and SCSI hard disks which may not be
5631 installed on the system. */
5632 if (errno == EACCES) {
5633 fprintf(stderr, _("Cannot open %s\n"), device);
5634 return;
5635 }
5636 }
5637}
5638
5639/* for fdisk -l: try all things in /proc/partitions
5640 that look like a partition name (do not end in a digit) */
5641static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005642tryprocpt(void)
5643{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005644 FILE *procpt;
5645 char line[100], ptname[100], devname[120], *s;
5646 int ma, mi, sz;
5647
Manuel Novoa III cad53642003-03-19 09:13:01 +00005648 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005649
5650 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005651 if (sscanf(line, " %d %d %d %[^\n ]",
5652 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005653 continue;
5654 for (s = ptname; *s; s++);
5655 if (isdigit(s[-1]))
5656 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005657 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005658 try(devname, 0);
5659 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005660#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005661 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005662#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005663}
5664
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005665#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005666static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005667unknown_command(int c)
5668{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005669 printf(_("%c: unknown command\n"), c);
5670}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005671#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005672
Rob Landleyb73451d2006-02-24 16:29:00 +00005673int fdisk_main(int argc, char **argv)
5674{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005675 int c;
5676#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5677 int optl = 0;
5678#endif
5679#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5680 int opts = 0;
5681#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005682 /*
5683 * Calls:
5684 * fdisk -v
5685 * fdisk -l [-b sectorsize] [-u] device ...
5686 * fdisk -s [partition] ...
5687 * fdisk [-b sectorsize] [-u] device
5688 *
5689 * Options -C, -H, -S set the geometry.
5690 *
5691 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005692 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5693#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5694 "s"
5695#endif
5696 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005697 switch (c) {
5698 case 'b':
5699 /* Ugly: this sector size is really per device,
5700 so cannot be combined with multiple disks,
5701 and te same goes for the C/H/S options.
5702 */
5703 sector_size = atoi(optarg);
5704 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005705 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005706 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005707 sector_offset = 2;
5708 user_set_sector_size = 1;
5709 break;
5710 case 'C':
5711 user_cylinders = atoi(optarg);
5712 break;
5713 case 'H':
5714 user_heads = atoi(optarg);
5715 if (user_heads <= 0 || user_heads >= 256)
5716 user_heads = 0;
5717 break;
5718 case 'S':
5719 user_sectors = atoi(optarg);
5720 if (user_sectors <= 0 || user_sectors >= 64)
5721 user_sectors = 0;
5722 break;
5723 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005724#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005725 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005726#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005727 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005728#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005729 case 's':
5730 opts = 1;
5731 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005732#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005733 case 'u':
5734 display_in_cyl_units = 0;
5735 break;
5736 case 'V':
5737 case 'v':
5738 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5739 return 0;
5740 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005741 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005742 }
5743 }
5744
5745#if 0
5746 printf(_("This kernel finds the sector size itself - "
5747 "-b option ignored\n"));
5748#else
5749 if (user_set_sector_size && argc-optind != 1)
5750 printf(_("Warning: the -b (set sector size) option should"
5751 " be used with one specified device\n"));
5752#endif
5753
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005754#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005755 if (optl) {
5756 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005757#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005758 type_open = O_RDONLY;
5759 if (argc > optind) {
5760 int k;
5761#if __GNUC__
5762 /* avoid gcc warning:
5763 variable `k' might be clobbered by `longjmp' */
5764 (void)&k;
5765#endif
5766 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005767 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005768 try(argv[k], 1);
5769 } else {
5770 /* we no longer have default device names */
5771 /* but, we can use /proc/partitions instead */
5772 tryprocpt();
5773 }
5774 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005775#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005776 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005777#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005778
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005779#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005780 if (opts) {
5781 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005782 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005783
5784 nowarn = 1;
5785 type_open = O_RDONLY;
5786
5787 opts = argc - optind;
5788 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005789 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005790
5791 for (j = optind; j < argc; j++) {
5792 disk_device = argv[j];
5793 if ((fd = open(disk_device, type_open)) < 0)
5794 fdisk_fatal(unable_to_open);
5795 if (ioctl(fd, BLKGETSIZE, &size))
5796 fdisk_fatal(ioctl_error);
5797 close(fd);
5798 if (opts == 1)
5799 printf("%ld\n", size/2);
5800 else
5801 printf("%s: %ld\n", argv[j], size/2);
5802 }
5803 return 0;
5804 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005805#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005806
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005807#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005808 if (argc-optind == 1)
5809 disk_device = argv[optind];
5810 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005811 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005812
5813 get_boot(fdisk);
5814
5815#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005816 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005817 /* OSF label, and no DOS label */
5818 printf(_("Detected an OSF/1 disklabel on %s, entering "
5819 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005820 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005821 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005822 /*Why do we do this? It seems to be counter-intuitive*/
5823 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005824 /* If we return we may want to make an empty DOS label? */
5825 }
5826#endif
5827
5828 while (1) {
5829 putchar('\n');
5830 c = tolower(read_char(_("Command (m for help): ")));
5831 switch (c) {
5832 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005833 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005834 toggle_active(get_partition(1, partitions));
5835#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005836 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005837 toggle_sunflags(get_partition(1, partitions),
5838 0x01);
5839#endif
5840#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005841 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005842 sgi_set_bootpartition(
5843 get_partition(1, partitions));
5844#endif
5845 else
5846 unknown_command(c);
5847 break;
5848 case 'b':
5849#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005850 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005851 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005852 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005853 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005854 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005855 printf(_("Boot file unchanged\n"));
5856 else
5857 sgi_set_bootfile(line_ptr);
5858 } else
5859#endif
5860#ifdef CONFIG_FEATURE_OSF_LABEL
5861 bselect();
5862#endif
5863 break;
5864 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005865 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005866 toggle_dos_compatibility_flag();
5867#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005868 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005869 toggle_sunflags(get_partition(1, partitions),
5870 0x10);
5871#endif
5872#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005873 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005874 sgi_set_swappartition(
5875 get_partition(1, partitions));
5876#endif
5877 else
5878 unknown_command(c);
5879 break;
5880 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005881 {
Eric Andersen040f4402003-07-30 08:40:37 +00005882 int j;
5883#ifdef CONFIG_FEATURE_SGI_LABEL
5884 /* If sgi_label then don't use get_existing_partition,
5885 let the user select a partition, since
5886 get_existing_partition() only works for Linux-like
5887 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005888 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005889 j = get_existing_partition(1, partitions);
5890 } else {
5891 j = get_partition(1, partitions);
5892 }
5893#else
5894 j = get_existing_partition(1, partitions);
5895#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005896 if (j >= 0)
5897 delete_partition(j);
5898 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005899 break;
5900 case 'i':
5901#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005902 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005903 create_sgiinfo();
5904 else
5905#endif
5906 unknown_command(c);
5907 case 'l':
5908 list_types(get_sys_types());
5909 break;
5910 case 'm':
5911 menu();
5912 break;
5913 case 'n':
5914 new_partition();
5915 break;
5916 case 'o':
5917 create_doslabel();
5918 break;
5919 case 'p':
5920 list_table(0);
5921 break;
5922 case 'q':
5923 close(fd);
5924 printf("\n");
5925 return 0;
5926 case 's':
5927#ifdef CONFIG_FEATURE_SUN_LABEL
5928 create_sunlabel();
5929#endif
5930 break;
5931 case 't':
5932 change_sysid();
5933 break;
5934 case 'u':
5935 change_units();
5936 break;
5937 case 'v':
5938 verify();
5939 break;
5940 case 'w':
5941 write_table(); /* does not return */
5942 break;
5943#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5944 case 'x':
5945#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005946 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005947 fprintf(stderr,
5948 _("\n\tSorry, no experts menu for SGI "
5949 "partition tables available.\n\n"));
5950 } else
5951#endif
5952
5953 xselect();
5954 break;
5955#endif
5956 default:
5957 unknown_command(c);
5958 menu();
5959 }
5960 }
5961 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005962#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005963}