blob: 3bf78ee04422702a17a355b3d239fdcb1e4385de [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002/* fdisk.c -- Partition table manipulator for Linux.
3 *
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
Mike Frysinger983e0ca2006-02-25 07:42:02 +00005 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00006 *
Rob Landleyb73451d2006-02-24 16:29:00 +00007 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00008 */
9
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000010/* Current changes have not compatibility with this version */
Eric Andersen99a75d12003-08-08 20:04:56 +000011#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000012
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000013
Rob Landley15d20a02006-05-29 05:00:44 +000014#define _(x) x
15
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000016#define PROC_PARTITIONS "/proc/partitions"
17
Eric Andersen256c4fd2004-05-19 09:00:00 +000018#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000019#include <sys/types.h>
20#include <sys/stat.h> /* stat */
21#include <ctype.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <errno.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <setjmp.h>
29#include <assert.h> /* assert */
30#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000031#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000032#include <sys/ioctl.h>
33#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000034#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000035
Eric Andersenacd244a2002-12-11 03:49:33 +000036#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
37
38/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000039#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000040
41#include <sys/utsname.h>
42
43#include "busybox.h"
44
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000045#define DKTYPENAMES
46
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000047/*
48 fdisk.h
49*/
50
51#define DEFAULT_SECTOR_SIZE 512
52#define MAX_SECTOR_SIZE 2048
53#define SECTOR_SIZE 512 /* still used in BSD code */
54#define MAXIMUM_PARTS 60
55
56#define ACTIVE_FLAG 0x80
57
58#define EXTENDED 0x05
59#define WIN98_EXTENDED 0x0f
60#define LINUX_PARTITION 0x81
61#define LINUX_SWAP 0x82
62#define LINUX_NATIVE 0x83
63#define LINUX_EXTENDED 0x85
64#define LINUX_LVM 0x8e
65#define LINUX_RAID 0xfd
66
67#define SUNOS_SWAP 3
68#define WHOLE_DISK 5
69
70#define IS_EXTENDED(i) \
71 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
72
73#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
74
75#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
76#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
77
Eric Andersen7495b0d2004-02-06 05:26:58 +000078#ifdef CONFIG_FEATURE_SUN_LABEL
79#define SCSI_IOCTL_GET_IDLUN 0x5382
80#endif
81
Eric Andersend3652bf2003-08-06 09:07:37 +000082
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000083/* including <linux/hdreg.h> also fails */
84struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000085 unsigned char heads;
86 unsigned char sectors;
87 unsigned short cylinders;
88 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000089};
90
91#define HDIO_GETGEO 0x0301 /* get device geometry */
92
93
94struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +000095 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000096};
97
Rob Landleyb73451d2006-02-24 16:29:00 +000098static uint sector_size = DEFAULT_SECTOR_SIZE;
99static uint user_set_sector_size;
100static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000101
102/*
103 * Raw disk label. For DOS-type partition tables the MBR,
104 * with descriptions of the primary partitions.
105 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000106#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000107static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000108#else
109# define MBRbuffer bb_common_bufsiz1
110#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000111
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000112#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000113static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000114#endif
115
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000116static uint heads, sectors, cylinders;
117static void update_units(void);
118
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000119
120/*
121 * return partition name - uses static storage unless buf is supplied
122 */
123static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000124partname(const char *dev, int pno, int lth)
125{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000126 static char buffer[80];
127 const char *p;
128 int w, wp;
129 int bufsiz;
130 char *bufp;
131
132 bufp = buffer;
133 bufsiz = sizeof(buffer);
134
135 w = strlen(dev);
136 p = "";
137
138 if (isdigit(dev[w-1]))
139 p = "p";
140
141 /* devfs kludge - note: fdisk partition names are not supposed
142 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000143 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000144 w -= 4;
145 p = "part";
146 }
147
148 wp = strlen(p);
149
150 if (lth) {
151 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
152 lth-wp-2, w, dev, p, pno);
153 } else {
154 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
155 }
156 return bufp;
157}
158
159struct partition {
160 unsigned char boot_ind; /* 0x80 - active */
161 unsigned char head; /* starting head */
162 unsigned char sector; /* starting sector */
163 unsigned char cyl; /* starting cylinder */
164 unsigned char sys_ind; /* What partition type */
165 unsigned char end_head; /* end head */
166 unsigned char end_sector; /* end sector */
167 unsigned char end_cyl; /* end cylinder */
168 unsigned char start4[4]; /* starting sector counting from 0 */
169 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000170} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000171
172enum failure {
173 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
174 unable_to_write
175};
176
Rob Landley5527b912006-02-25 03:46:10 +0000177enum label_type{
178 label_dos, label_sun, label_sgi, label_aix, label_osf
179};
180
Rob Landleyb73451d2006-02-24 16:29:00 +0000181enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000182
Rob Landley5527b912006-02-25 03:46:10 +0000183static enum label_type current_label_type;
184
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000185static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000186static int fd; /* the disk */
187static int partitions = 4; /* maximum partition + 1 */
188static uint display_in_cyl_units = 1;
189static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000190#ifdef CONFIG_FEATURE_FDISK_WRITABLE
191static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000192static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000193static void reread_partition_table(int leave);
194static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000195static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000196static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000197static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000198#endif
199static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000200static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000201static void get_geometry(void);
202static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000203
204#define PLURAL 0
205#define SINGULAR 1
206
207#define hex_val(c) ({ \
208 char _c = (c); \
209 isdigit(_c) ? _c - '0' : \
210 tolower(_c) + 10 - 'a'; \
211 })
212
213
214#define LINE_LENGTH 800
215#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
216 (n) * sizeof(struct partition)))
217#define sector(s) ((s) & 0x3f)
218#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
219
220#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
221 ((h) + heads * cylinder(s,c)))
222#define set_hsc(h,s,c,sector) { \
223 s = sector % sectors + 1; \
224 sector /= sectors; \
225 h = sector % heads; \
226 sector /= heads; \
227 c = sector & 0xff; \
228 s |= (sector >> 2) & 0xc0; \
229 }
230
231
Eric Andersend9261492004-06-28 23:50:31 +0000232static int32_t get_start_sect(const struct partition *p);
233static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000234
235/*
236 * per partition table entry data
237 *
238 * The four primary partitions have the same sectorbuffer (MBRbuffer)
239 * and have NULL ext_pointer.
240 * Each logical partition table entry has two pointers, one for the
241 * partition and one link to the next one.
242 */
243static struct pte {
244 struct partition *part_table; /* points into sectorbuffer */
245 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000246#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000247 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000248#endif
Eric Andersend9261492004-06-28 23:50:31 +0000249 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000250 char *sectorbuffer; /* disk sector contents */
251} ptes[MAXIMUM_PARTS];
252
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000253
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000254#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000255static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000256set_all_unchanged(void)
257{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000258 int i;
259
260 for (i = 0; i < MAXIMUM_PARTS; i++)
261 ptes[i].changed = 0;
262}
263
264static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000265set_changed(int i)
266{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000267 ptes[i].changed = 1;
268}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000269#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000270
271#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
272static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000273get_part_table(int i)
274{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000275 return ptes[i].part_table;
276}
277#endif
278
279static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000280str_units(int n)
281{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000282 if (n == 1)
283 return display_in_cyl_units ? _("cylinder") : _("sector");
284 else
285 return display_in_cyl_units ? _("cylinders") : _("sectors");
286}
287
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000288static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000289valid_part_table_flag(const char *mbuffer) {
290 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000291 return (b[510] == 0x55 && b[511] == 0xaa);
292}
293
294#ifdef CONFIG_FEATURE_FDISK_WRITABLE
295static char line_buffer[LINE_LENGTH];
296
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000297/* read line; return 0 or first char */
298static int
299read_line(void)
300{
301 static int got_eof = 0;
302
303 fflush (stdout); /* requested by niles@scyld.com */
304 line_ptr = line_buffer;
305 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
306 if (feof(stdin))
307 got_eof++; /* user typed ^D ? */
308 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000309 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
310 exit(1);
311 }
312 return 0;
313 }
314 while (*line_ptr && !isgraph(*line_ptr))
315 line_ptr++;
316 return *line_ptr;
317}
318
319static char
320read_char(const char *mesg)
321{
322 do {
323 fputs(mesg, stdout);
324 } while (!read_line());
325 return *line_ptr;
326}
327
328static char
329read_chars(const char *mesg)
330{
331 fputs(mesg, stdout);
332 if (!read_line()) {
333 *line_ptr = '\n';
334 line_ptr[1] = 0;
335 }
336 return *line_ptr;
337}
338
339static int
340read_hex(const struct systypes *sys)
341{
342 int hex;
343
Rob Landleyb73451d2006-02-24 16:29:00 +0000344 while (1) {
345 read_char(_("Hex code (type L to list codes): "));
346 if (*line_ptr == 'l' || *line_ptr == 'L')
347 list_types(sys);
348 else if (isxdigit (*line_ptr)) {
349 hex = 0;
350 do
351 hex = hex << 4 | hex_val(*line_ptr++);
352 while (isxdigit(*line_ptr));
353 return hex;
354 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000355 }
356}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000357#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000358
359#ifdef CONFIG_FEATURE_AIX_LABEL
360/*
361 * Copyright (C) Andreas Neuper, Sep 1998.
362 * This file may be redistributed under
363 * the terms of the GNU Public License.
364 */
365
366typedef struct {
367 unsigned int magic; /* expect AIX_LABEL_MAGIC */
368 unsigned int fillbytes1[124];
369 unsigned int physical_volume_id;
370 unsigned int fillbytes2[124];
371} aix_partition;
372
373#define AIX_LABEL_MAGIC 0xc9c2d4c1
374#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
375#define AIX_INFO_MAGIC 0x00072959
376#define AIX_INFO_MAGIC_SWAPPED 0x59290700
377
378#define aixlabel ((aix_partition *)MBRbuffer)
379
380
381/*
382 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000383 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
384 * Internationalization
385 *
386 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
387 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000388*/
389
Rob Landleyb73451d2006-02-24 16:29:00 +0000390static int aix_other_endian;
391static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000392
393/*
394 * only dealing with free blocks here
395 */
396
397static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000398aix_info(void)
399{
400 puts(
401 _("\n\tThere is a valid AIX label on this disk.\n"
402 "\tUnfortunately Linux cannot handle these\n"
403 "\tdisks at the moment. Nevertheless some\n"
404 "\tadvice:\n"
405 "\t1. fdisk will destroy its contents on write.\n"
406 "\t2. Be sure that this disk is NOT a still vital\n"
407 "\t part of a volume group. (Otherwise you may\n"
408 "\t erase the other disks as well, if unmirrored.)\n"
409 "\t3. Before deleting this physical volume be sure\n"
410 "\t to remove the disk logically from your AIX\n"
411 "\t machine. (Otherwise you become an AIXpert).")
412 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000413}
414
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000415static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000416check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000417{
Rob Landleyb73451d2006-02-24 16:29:00 +0000418 if (aixlabel->magic != AIX_LABEL_MAGIC &&
419 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000420 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000421 aix_other_endian = 0;
422 return 0;
423 }
424 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
425 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000426 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000427 partitions = 1016;
428 aix_volumes = 15;
429 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000430 /*aix_nolabel();*/ /* %% */
431 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000432 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000433}
434#endif /* AIX_LABEL */
435
436#ifdef CONFIG_FEATURE_OSF_LABEL
437/*
438 * Copyright (c) 1987, 1988 Regents of the University of California.
439 * All rights reserved.
440 *
441 * Redistribution and use in source and binary forms, with or without
442 * modification, are permitted provided that the following conditions
443 * are met:
444 * 1. Redistributions of source code must retain the above copyright
445 * notice, this list of conditions and the following disclaimer.
446 * 2. Redistributions in binary form must reproduce the above copyright
447 * notice, this list of conditions and the following disclaimer in the
448 * documentation and/or other materials provided with the distribution.
449 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000450 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000451 * This product includes software developed by the University of
452 * California, Berkeley and its contributors.
453 * 4. Neither the name of the University nor the names of its contributors
454 * may be used to endorse or promote products derived from this software
455 * without specific prior written permission.
456 *
457 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
458 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
459 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
460 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
461 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
462 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
463 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
464 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
465 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
466 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
467 * SUCH DAMAGE.
468 */
469
470
471#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000472#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000473#endif
474
475#ifndef BSD_MAXPARTITIONS
476#define BSD_MAXPARTITIONS 16
477#endif
478
479#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
480
Mike Frysingerc340ea12006-06-30 02:53:56 +0000481#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__m68k__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000482#define BSD_LABELSECTOR 1
483#define BSD_LABELOFFSET 0
484#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
485#define BSD_LABELSECTOR 0
486#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000487#elif defined (__s390__) || defined (__s390x__)
488#define BSD_LABELSECTOR 1
489#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000490#else
491#error unknown architecture
492#endif
493
494#define BSD_BBSIZE 8192 /* size of boot area, with label */
495#define BSD_SBSIZE 8192 /* max size of fs superblock */
496
497struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000498 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000499 int16_t d_type; /* drive type */
500 int16_t d_subtype; /* controller/d_type specific */
501 char d_typename[16]; /* type name, e.g. "eagle" */
502 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000503 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000504 uint32_t d_secsize; /* # of bytes per sector */
505 uint32_t d_nsectors; /* # of data sectors per track */
506 uint32_t d_ntracks; /* # of tracks per cylinder */
507 uint32_t d_ncylinders; /* # of data cylinders per unit */
508 uint32_t d_secpercyl; /* # of data sectors per cylinder */
509 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000510 /*
511 * Spares (bad sector replacements) below
512 * are not counted in d_nsectors or d_secpercyl.
513 * Spare sectors are assumed to be physical sectors
514 * which occupy space at the end of each track and/or cylinder.
515 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000516 uint16_t d_sparespertrack; /* # of spare sectors per track */
517 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000518 /*
519 * Alternate cylinders include maintenance, replacement,
520 * configuration description areas, etc.
521 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000522 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000523
524 /* hardware characteristics: */
525 /*
526 * d_interleave, d_trackskew and d_cylskew describe perturbations
527 * in the media format used to compensate for a slow controller.
528 * Interleave is physical sector interleave, set up by the formatter
529 * or controller when formatting. When interleaving is in use,
530 * logically adjacent sectors are not physically contiguous,
531 * but instead are separated by some number of sectors.
532 * It is specified as the ratio of physical sectors traversed
533 * per logical sector. Thus an interleave of 1:1 implies contiguous
534 * layout, while 2:1 implies that logical sector 0 is separated
535 * by one sector from logical sector 1.
536 * d_trackskew is the offset of sector 0 on track N
537 * relative to sector 0 on track N-1 on the same cylinder.
538 * Finally, d_cylskew is the offset of sector 0 on cylinder N
539 * relative to sector 0 on cylinder N-1.
540 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000541 uint16_t d_rpm; /* rotational speed */
542 uint16_t d_interleave; /* hardware sector interleave */
543 uint16_t d_trackskew; /* sector 0 skew, per track */
544 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
545 uint32_t d_headswitch; /* head switch time, usec */
546 uint32_t d_trkseek; /* track-to-track seek, usec */
547 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000548#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000549 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000550#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000551 uint32_t d_spare[NSPARE]; /* reserved for future use */
552 uint32_t d_magic2; /* the magic number (again) */
553 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000554 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000555 uint16_t d_npartitions; /* number of partitions in following */
556 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
557 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000558 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000559 uint32_t p_size; /* number of sectors in partition */
560 uint32_t p_offset; /* starting sector */
561 uint32_t p_fsize; /* filesystem basic fragment size */
562 uint8_t p_fstype; /* filesystem type, see below */
563 uint8_t p_frag; /* filesystem fragments per block */
564 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000565 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
566};
567
568/* d_type values: */
569#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
570#define BSD_DTYPE_MSCP 2 /* MSCP */
571#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
572#define BSD_DTYPE_SCSI 4 /* SCSI */
573#define BSD_DTYPE_ESDI 5 /* ESDI interface */
574#define BSD_DTYPE_ST506 6 /* ST506 etc. */
575#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
576#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
577#define BSD_DTYPE_FLOPPY 10 /* floppy */
578
579/* d_subtype values: */
580#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
581#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
582#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
583
584#ifdef DKTYPENAMES
585static const char * const xbsd_dktypenames[] = {
586 "unknown",
587 "SMD",
588 "MSCP",
589 "old DEC",
590 "SCSI",
591 "ESDI",
592 "ST506",
593 "HP-IB",
594 "HP-FL",
595 "type 9",
596 "floppy",
597 0
598};
599#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
600#endif
601
602/*
603 * Filesystem type and version.
604 * Used to interpret other filesystem-specific
605 * per-partition information.
606 */
607#define BSD_FS_UNUSED 0 /* unused */
608#define BSD_FS_SWAP 1 /* swap */
609#define BSD_FS_V6 2 /* Sixth Edition */
610#define BSD_FS_V7 3 /* Seventh Edition */
611#define BSD_FS_SYSV 4 /* System V */
612#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
613#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
614#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
615#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
616#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
617#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
618#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
619#define BSD_FS_ISOFS BSD_FS_ISO9660
620#define BSD_FS_BOOT 13 /* partition contains bootstrap */
621#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
622#define BSD_FS_HFS 15 /* Macintosh HFS */
623#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
624
625/* this is annoying, but it's also the way it is :-( */
626#ifdef __alpha__
627#define BSD_FS_EXT2 8 /* ext2 file system */
628#else
629#define BSD_FS_MSDOS 8 /* MS-DOS file system */
630#endif
631
632#ifdef DKTYPENAMES
633static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000634 { "\x00" "unused" }, /* BSD_FS_UNUSED */
635 { "\x01" "swap" }, /* BSD_FS_SWAP */
636 { "\x02" "Version 6" }, /* BSD_FS_V6 */
637 { "\x03" "Version 7" }, /* BSD_FS_V7 */
638 { "\x04" "System V" }, /* BSD_FS_SYSV */
639 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
640 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
641 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000642#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000643 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000644#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000645 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000646#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000647 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
648 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
649 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
650 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
651 { "\x0d" "boot" }, /* BSD_FS_BOOT */
652 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
653 { "\x0f" "HFS" }, /* BSD_FS_HFS */
654 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
655 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000656};
657#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
658
659#endif
660
661/*
662 * flags shared by various drives:
663 */
664#define BSD_D_REMOVABLE 0x01 /* removable media */
665#define BSD_D_ECC 0x02 /* supports ECC */
666#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
667#define BSD_D_RAMDISK 0x08 /* disk emulator */
668#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
669#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
670
671#endif /* OSF_LABEL */
672
673/*
674 * Copyright (C) Andreas Neuper, Sep 1998.
675 * This file may be modified and redistributed under
676 * the terms of the GNU Public License.
677 */
678
679struct device_parameter { /* 48 bytes */
680 unsigned char skew;
681 unsigned char gap1;
682 unsigned char gap2;
683 unsigned char sparecyl;
684 unsigned short pcylcount;
685 unsigned short head_vol0;
686 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
687 unsigned char cmd_tag_queue_depth;
688 unsigned char unused0;
689 unsigned short unused1;
690 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
691 unsigned short bytes;
692 unsigned short ilfact;
693 unsigned int flags; /* controller flags */
694 unsigned int datarate;
695 unsigned int retries_on_error;
696 unsigned int ms_per_word;
697 unsigned short xylogics_gap1;
698 unsigned short xylogics_syncdelay;
699 unsigned short xylogics_readdelay;
700 unsigned short xylogics_gap2;
701 unsigned short xylogics_readgate;
702 unsigned short xylogics_writecont;
703};
704
705#define SGI_VOLHDR 0x00
706/* 1 and 2 were used for drive types no longer supported by SGI */
707#define SGI_SWAP 0x03
708/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
709#define SGI_VOLUME 0x06
710#define SGI_EFS 0x07
711#define SGI_LVOL 0x08
712#define SGI_RLVOL 0x09
713#define SGI_XFS 0x0a
714#define SGI_XFSLOG 0x0b
715#define SGI_XLV 0x0c
716#define SGI_XVM 0x0d
717#define ENTIRE_DISK SGI_VOLUME
718/*
719 * controller flags
720 */
721#define SECTOR_SLIP 0x01
722#define SECTOR_FWD 0x02
723#define TRACK_FWD 0x04
724#define TRACK_MULTIVOL 0x08
725#define IGNORE_ERRORS 0x10
726#define RESEEK 0x20
727#define ENABLE_CMDTAGQ 0x40
728
729typedef struct {
730 unsigned int magic; /* expect SGI_LABEL_MAGIC */
731 unsigned short boot_part; /* active boot partition */
732 unsigned short swap_part; /* active swap partition */
733 unsigned char boot_file[16]; /* name of the bootfile */
734 struct device_parameter devparam; /* 1 * 48 bytes */
735 struct volume_directory { /* 15 * 16 bytes */
736 unsigned char vol_file_name[8]; /* a character array */
737 unsigned int vol_file_start; /* number of logical block */
738 unsigned int vol_file_size; /* number of bytes */
739 } directory[15];
740 struct sgi_partition { /* 16 * 12 bytes */
741 unsigned int num_sectors; /* number of blocks */
742 unsigned int start_sector; /* must be cylinder aligned */
743 unsigned int id;
744 } partitions[16];
745 unsigned int csum;
746 unsigned int fillbytes;
747} sgi_partition;
748
749typedef struct {
750 unsigned int magic; /* looks like a magic number */
751 unsigned int a2;
752 unsigned int a3;
753 unsigned int a4;
754 unsigned int b1;
755 unsigned short b2;
756 unsigned short b3;
757 unsigned int c[16];
758 unsigned short d[3];
759 unsigned char scsi_string[50];
760 unsigned char serial[137];
761 unsigned short check1816;
762 unsigned char installer[225];
763} sgiinfo;
764
765#define SGI_LABEL_MAGIC 0x0be5a941
766#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
767#define SGI_INFO_MAGIC 0x00072959
768#define SGI_INFO_MAGIC_SWAPPED 0x59290700
769#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000770 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000771#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000772 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000773
774#define sgilabel ((sgi_partition *)MBRbuffer)
775#define sgiparam (sgilabel->devparam)
776
777typedef struct {
778 unsigned char info[128]; /* Informative text string */
779 unsigned char spare0[14];
780 struct sun_info {
781 unsigned char spare1;
782 unsigned char id;
783 unsigned char spare2;
784 unsigned char flags;
785 } infos[8];
786 unsigned char spare1[246]; /* Boot information etc. */
787 unsigned short rspeed; /* Disk rotational speed */
788 unsigned short pcylcount; /* Physical cylinder count */
789 unsigned short sparecyl; /* extra sects per cylinder */
790 unsigned char spare2[4]; /* More magic... */
791 unsigned short ilfact; /* Interleave factor */
792 unsigned short ncyl; /* Data cylinder count */
793 unsigned short nacyl; /* Alt. cylinder count */
794 unsigned short ntrks; /* Tracks per cylinder */
795 unsigned short nsect; /* Sectors per track */
796 unsigned char spare3[4]; /* Even more magic... */
797 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000798 uint32_t start_cylinder;
799 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000800 } partitions[8];
801 unsigned short magic; /* Magic number */
802 unsigned short csum; /* Label xor'd checksum */
803} sun_partition;
804
Eric Andersen040f4402003-07-30 08:40:37 +0000805
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000806#define SUN_LABEL_MAGIC 0xDABE
807#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
808#define sunlabel ((sun_partition *)MBRbuffer)
809#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000810 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000811#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000812 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000813
Eric Andersend3652bf2003-08-06 09:07:37 +0000814
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000815#ifdef CONFIG_FEATURE_OSF_LABEL
816/*
817 Changes:
818 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
819
820 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
821 support for OSF/1 disklabels on Alpha.
822 Also fixed unaligned accesses in alpha_bootblock_checksum()
823*/
824
825#define FREEBSD_PARTITION 0xa5
826#define NETBSD_PARTITION 0xa9
827
Rob Landleyb73451d2006-02-24 16:29:00 +0000828static void xbsd_delete_part(void);
829static void xbsd_new_part(void);
830static void xbsd_write_disklabel(void);
831static int xbsd_create_disklabel(void);
832static void xbsd_edit_disklabel(void);
833static void xbsd_write_bootstrap(void);
834static void xbsd_change_fstype(void);
835static int xbsd_get_part_index(int max);
836static int xbsd_check_new_partition(int *i);
837static void xbsd_list_types(void);
838static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
839static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
840static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
841static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000842
843#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000844static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000845#endif
846
847#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000848static int xbsd_translate_fstype(int linux_type);
849static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000850static struct partition *xbsd_part;
851static int xbsd_part_index;
852#endif
853
854#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000855/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000856static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000857#else
858static char disklabelbuffer[BSD_BBSIZE];
859#endif
860
861static struct xbsd_disklabel xbsd_dlabel;
862
863#define bsd_cround(n) \
864 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
865
866/*
867 * Test whether the whole disk has BSD disk label magic.
868 *
869 * Note: often reformatting with DOS-type label leaves the BSD magic,
870 * so this does not mean that there is a BSD disk label.
871 */
872static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000873check_osf_label(void)
874{
875 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000876 return 0;
877 return 1;
878}
879
880static void xbsd_print_disklabel(int);
881
882static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000883btrydev(const char * dev)
884{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000885 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
886 return -1;
887 printf(_("\nBSD label for device: %s\n"), dev);
888 xbsd_print_disklabel (0);
889 return 0;
890}
891
892static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000893bmenu(void)
894{
895 puts (_("Command action"));
896 puts (_("\td\tdelete a BSD partition"));
897 puts (_("\te\tedit drive data"));
898 puts (_("\ti\tinstall bootstrap"));
899 puts (_("\tl\tlist known filesystem types"));
900 puts (_("\tm\tprint this menu"));
901 puts (_("\tn\tadd a new BSD partition"));
902 puts (_("\tp\tprint BSD partition table"));
903 puts (_("\tq\tquit without saving changes"));
904 puts (_("\tr\treturn to main menu"));
905 puts (_("\ts\tshow complete disklabel"));
906 puts (_("\tt\tchange a partition's filesystem id"));
907 puts (_("\tu\tchange units (cylinders/sectors)"));
908 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000909#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000910 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000911#endif
912}
913
914#if !defined (__alpha__)
915static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000916hidden(int type)
917{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000918 return type ^ 0x10;
919}
920
921static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000922is_bsd_partition_type(int type)
923{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000924 return (type == FREEBSD_PARTITION ||
925 type == hidden(FREEBSD_PARTITION) ||
926 type == NETBSD_PARTITION ||
927 type == hidden(NETBSD_PARTITION));
928}
929#endif
930
931static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000932bselect(void)
933{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000934#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000935 int t, ss;
936 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000937
Rob Landleyb73451d2006-02-24 16:29:00 +0000938 for (t = 0; t < 4; t++) {
939 p = get_part_table(t);
940 if (p && is_bsd_partition_type(p->sys_ind)) {
941 xbsd_part = p;
942 xbsd_part_index = t;
943 ss = get_start_sect(xbsd_part);
944 if (ss == 0) {
945 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
946 partname(disk_device, t+1, 0));
947 return;
948 }
949 printf(_("Reading disklabel of %s at sector %d.\n"),
950 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
951 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
952 if (xbsd_create_disklabel() == 0)
953 return;
954 break;
955 }
956 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000957
Rob Landleyb73451d2006-02-24 16:29:00 +0000958 if (t == 4) {
959 printf(_("There is no *BSD partition on %s.\n"), disk_device);
960 return;
961 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000962
963#elif defined (__alpha__)
964
Rob Landleyb73451d2006-02-24 16:29:00 +0000965 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
966 if (xbsd_create_disklabel() == 0)
967 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000968
969#endif
970
Rob Landleyb73451d2006-02-24 16:29:00 +0000971 while (1) {
972 putchar('\n');
973 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
974 case 'd':
975 xbsd_delete_part();
976 break;
977 case 'e':
978 xbsd_edit_disklabel();
979 break;
980 case 'i':
981 xbsd_write_bootstrap();
982 break;
983 case 'l':
984 xbsd_list_types();
985 break;
986 case 'n':
987 xbsd_new_part();
988 break;
989 case 'p':
990 xbsd_print_disklabel(0);
991 break;
992 case 'q':
993 close(fd);
994 exit(EXIT_SUCCESS);
995 case 'r':
996 return;
997 case 's':
998 xbsd_print_disklabel(1);
999 break;
1000 case 't':
1001 xbsd_change_fstype();
1002 break;
1003 case 'u':
1004 change_units();
1005 break;
1006 case 'w':
1007 xbsd_write_disklabel();
1008 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001009#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001010 case 'x':
1011 xbsd_link_part();
1012 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001013#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001014 default:
1015 bmenu();
1016 break;
1017 }
1018 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001019}
1020
1021static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001022xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001023{
Rob Landleyb73451d2006-02-24 16:29:00 +00001024 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001025
Rob Landleyb73451d2006-02-24 16:29:00 +00001026 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1027 xbsd_dlabel.d_partitions[i].p_size = 0;
1028 xbsd_dlabel.d_partitions[i].p_offset = 0;
1029 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1030 if (xbsd_dlabel.d_npartitions == i + 1)
1031 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1032 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001033}
1034
1035static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001036xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001037{
Rob Landleyb73451d2006-02-24 16:29:00 +00001038 off_t begin, end;
1039 char mesg[256];
1040 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001041
Rob Landleyb73451d2006-02-24 16:29:00 +00001042 if (!xbsd_check_new_partition(&i))
1043 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001044
1045#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001046 begin = get_start_sect(xbsd_part);
1047 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001048#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001049 begin = 0;
1050 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001051#endif
1052
Rob Landleyb73451d2006-02-24 16:29:00 +00001053 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1054 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1055 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001056
Rob Landleyb73451d2006-02-24 16:29:00 +00001057 if (display_in_cyl_units)
1058 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001059
Rob Landleyb73451d2006-02-24 16:29:00 +00001060 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1061 str_units(SINGULAR));
1062 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1063 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001064
Rob Landleyb73451d2006-02-24 16:29:00 +00001065 if (display_in_cyl_units)
1066 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001067
Rob Landleyb73451d2006-02-24 16:29:00 +00001068 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1069 xbsd_dlabel.d_partitions[i].p_offset = begin;
1070 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001071}
1072
1073static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001074xbsd_print_disklabel(int show_all)
1075{
1076 struct xbsd_disklabel *lp = &xbsd_dlabel;
1077 struct xbsd_partition *pp;
1078 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001079
Rob Landleyb73451d2006-02-24 16:29:00 +00001080 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001081#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001082 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001083#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001084 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001085#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001086 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1087 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1088 else
1089 printf(_("type: %d\n"), lp->d_type);
1090 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1091 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1092 printf(_("flags:"));
1093 if (lp->d_flags & BSD_D_REMOVABLE)
1094 printf(_(" removable"));
1095 if (lp->d_flags & BSD_D_ECC)
1096 printf(_(" ecc"));
1097 if (lp->d_flags & BSD_D_BADSECT)
1098 printf(_(" badsect"));
1099 printf("\n");
1100 /* On various machines the fields of *lp are short/int/long */
1101 /* In order to avoid problems, we cast them all to long. */
1102 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1103 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1104 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1105 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1106 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1107 printf(_("rpm: %d\n"), lp->d_rpm);
1108 printf(_("interleave: %d\n"), lp->d_interleave);
1109 printf(_("trackskew: %d\n"), lp->d_trackskew);
1110 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1111 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1112 (long) lp->d_headswitch);
1113 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1114 (long) lp->d_trkseek);
1115 printf(_("drivedata: "));
1116 for (i = NDDATA - 1; i >= 0; i--)
1117 if (lp->d_drivedata[i])
1118 break;
1119 if (i < 0)
1120 i = 0;
1121 for (j = 0; j <= i; j++)
1122 printf("%ld ", (long) lp->d_drivedata[j]);
1123 }
1124 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1125 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1126 pp = lp->d_partitions;
1127 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1128 if (pp->p_size) {
1129 if (display_in_cyl_units && lp->d_secpercyl) {
1130 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1131 'a' + i,
1132 (long) pp->p_offset / lp->d_secpercyl + 1,
1133 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1134 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1135 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1136 (long) pp->p_size / lp->d_secpercyl,
1137 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1138 );
1139 } else {
1140 printf(" %c: %8ld %8ld %8ld ",
1141 'a' + i,
1142 (long) pp->p_offset,
1143 (long) pp->p_offset + pp->p_size - 1,
1144 (long) pp->p_size
1145 );
1146 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001147
Rob Landleyb73451d2006-02-24 16:29:00 +00001148 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1149 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1150 else
1151 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001152
Rob Landleyb73451d2006-02-24 16:29:00 +00001153 switch (pp->p_fstype) {
1154 case BSD_FS_UNUSED:
1155 printf(" %5ld %5ld %5.5s ",
1156 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1157 break;
1158 case BSD_FS_BSDFFS:
1159 printf(" %5ld %5ld %5d ",
1160 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1161 break;
1162 default:
1163 printf("%22.22s", "");
1164 break;
1165 }
1166 printf("\n");
1167 }
1168 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001169}
1170
1171static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001172xbsd_write_disklabel(void)
1173{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001174#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001175 printf(_("Writing disklabel to %s.\n"), disk_device);
1176 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001177#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001178 printf(_("Writing disklabel to %s.\n"),
1179 partname(disk_device, xbsd_part_index + 1, 0));
1180 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001181#endif
1182 reread_partition_table(0); /* no exit yet */
1183}
1184
1185static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001186xbsd_create_disklabel(void)
1187{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001188 char c;
1189
1190#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001191 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001192#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001193 fprintf(stderr, _("%s contains no disklabel.\n"),
1194 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001195#endif
1196
1197 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001198 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001199 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001200 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001201#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001202 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001203 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001204#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001205 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001206#endif
1207 ) == 1) {
1208 xbsd_print_disklabel (1);
1209 return 1;
1210 } else
1211 return 0;
1212 } else if (c == 'n')
1213 return 0;
1214 }
1215}
1216
1217static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001218edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001219{
Rob Landleyb73451d2006-02-24 16:29:00 +00001220 do {
1221 fputs(mesg, stdout);
1222 printf(" (%d): ", def);
1223 if (!read_line())
1224 return def;
Denis Vlasenko13858992006-10-08 12:49:22 +00001225 } while (!isdigit(*line_ptr));
Rob Landleyb73451d2006-02-24 16:29:00 +00001226 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001227}
1228
1229static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001230xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001231{
Rob Landleyb73451d2006-02-24 16:29:00 +00001232 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001233
Rob Landleyb73451d2006-02-24 16:29:00 +00001234 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001235
1236#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001237 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1238 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1239 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1240 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001241#endif
1242
Rob Landleyb73451d2006-02-24 16:29:00 +00001243 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1244 while (1) {
1245 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1246 _("sectors/cylinder"));
1247 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1248 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001249
Rob Landleyb73451d2006-02-24 16:29:00 +00001250 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1251 }
1252 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1253 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1254 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1255 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1256 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1257 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001258
Rob Landleyb73451d2006-02-24 16:29:00 +00001259 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001260}
1261
1262static int
1263xbsd_get_bootstrap (char *path, void *ptr, int size)
1264{
Rob Landleyb73451d2006-02-24 16:29:00 +00001265 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001266
Rob Landleyb73451d2006-02-24 16:29:00 +00001267 if ((fdb = open (path, O_RDONLY)) < 0) {
1268 perror(path);
1269 return 0;
1270 }
1271 if (read(fdb, ptr, size) < 0) {
1272 perror(path);
1273 close(fdb);
1274 return 0;
1275 }
1276 printf(" ... %s\n", path);
1277 close(fdb);
1278 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001279}
1280
1281static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001282sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001283{
Rob Landleyb73451d2006-02-24 16:29:00 +00001284 printf(_("\nSyncing disks.\n"));
1285 sync();
1286 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001287}
1288
1289static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001290xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291{
Rob Landleyb73451d2006-02-24 16:29:00 +00001292 char *bootdir = BSD_LINUX_BOOTDIR;
1293 char path[MAXPATHLEN];
1294 char *dkbasename;
1295 struct xbsd_disklabel dl;
1296 char *d, *p, *e;
1297 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001298
Rob Landleyb73451d2006-02-24 16:29:00 +00001299 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1300 dkbasename = "sd";
1301 else
1302 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001303
Rob Landleyb73451d2006-02-24 16:29:00 +00001304 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1305 dkbasename, dkbasename, dkbasename);
1306 if (read_line()) {
1307 line_ptr[strlen(line_ptr)-1] = '\0';
1308 dkbasename = line_ptr;
1309 }
1310 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1311 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1312 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001313
Rob Landleyb73451d2006-02-24 16:29:00 +00001314/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1315 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
Mike Frysinger1a540302006-04-16 05:58:21 +00001316 memmove(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001317
Rob Landleyb73451d2006-02-24 16:29:00 +00001318/* The disklabel will be overwritten by 0's from bootxx anyway */
1319 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001320
Rob Landleyb73451d2006-02-24 16:29:00 +00001321 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1322 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001323 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001324 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001325
Rob Landleyb73451d2006-02-24 16:29:00 +00001326 e = d + sizeof(struct xbsd_disklabel);
1327 for (p = d; p < e; p++)
1328 if (*p) {
1329 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1330 exit(EXIT_FAILURE);
1331 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001332
Mike Frysinger1a540302006-04-16 05:58:21 +00001333 memmove(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001334
1335#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001336 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001337#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001338 sector = 0;
1339 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001340#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001341 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001342#endif
1343
Rob Landleyb73451d2006-02-24 16:29:00 +00001344 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1345 fdisk_fatal(unable_to_seek);
1346 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1347 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001348
1349#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001350 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001351#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001352 printf(_("Bootstrap installed on %s.\n"),
1353 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001354#endif
1355
Rob Landleyb73451d2006-02-24 16:29:00 +00001356 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001357}
1358
1359static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001360xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001361{
Rob Landleyb73451d2006-02-24 16:29:00 +00001362 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001363
Rob Landleyb73451d2006-02-24 16:29:00 +00001364 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1365 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001366}
1367
1368static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001369xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001370{
Rob Landleyb73451d2006-02-24 16:29:00 +00001371 char prompt[256];
1372 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373
Rob Landleyb73451d2006-02-24 16:29:00 +00001374 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1375 do
1376 l = tolower(read_char(prompt));
1377 while (l < 'a' || l > 'a' + max - 1);
1378 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001379}
1380
1381static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001382xbsd_check_new_partition(int *i)
1383{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001384 /* room for more? various BSD flavours have different maxima */
1385 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1386 int t;
1387
1388 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1389 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1390 break;
1391
1392 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001393 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001394 "has been created\n"));
1395 return 0;
1396 }
1397 }
1398
1399 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1400
1401 if (*i >= xbsd_dlabel.d_npartitions)
1402 xbsd_dlabel.d_npartitions = (*i) + 1;
1403
1404 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001405 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001406 return 0;
1407 }
1408
1409 return 1;
1410}
1411
1412static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001413xbsd_list_types(void)
1414{
1415 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001416}
1417
1418static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001419xbsd_dkcksum(struct xbsd_disklabel *lp)
1420{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001421 u_short *start, *end;
1422 u_short sum = 0;
1423
1424 start = (u_short *) lp;
1425 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1426 while (start < end)
1427 sum ^= *start++;
1428 return sum;
1429}
1430
1431static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001432xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1433{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001434 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001435
Rob Landleyb73451d2006-02-24 16:29:00 +00001436 get_geometry();
1437 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001438
Rob Landleyb73451d2006-02-24 16:29:00 +00001439 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001440
Rob Landleyb73451d2006-02-24 16:29:00 +00001441 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1442 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001443 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001444 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001445
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001446#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001447 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001448#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001449 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001450#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001451 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1452 d->d_nsectors = sectors; /* sectors/track */
1453 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1454 d->d_ncylinders = cylinders;
1455 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1456 if (d->d_secpercyl == 0)
1457 d->d_secpercyl = 1; /* avoid segfaults */
1458 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001459
Rob Landleyb73451d2006-02-24 16:29:00 +00001460 d->d_rpm = 3600;
1461 d->d_interleave = 1;
1462 d->d_trackskew = 0;
1463 d->d_cylskew = 0;
1464 d->d_headswitch = 0;
1465 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001466
Rob Landleyb73451d2006-02-24 16:29:00 +00001467 d->d_magic2 = BSD_DISKMAGIC;
1468 d->d_bbsize = BSD_BBSIZE;
1469 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001470
1471#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001472 d->d_npartitions = 4;
1473 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001474 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001475 pp->p_offset = get_start_sect(p);
1476 pp->p_size = get_nr_sects(p);
1477 pp->p_fstype = BSD_FS_UNUSED;
1478 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001479 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001480 pp->p_offset = 0;
1481 pp->p_size = d->d_secperunit;
1482 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001483#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001484 d->d_npartitions = 3;
1485 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001486 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001487 pp->p_offset = 0;
1488 pp->p_size = d->d_secperunit;
1489 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001490#endif
1491
1492 return 1;
1493}
1494
1495/*
1496 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1497 * If it has the right magic, return 1.
1498 */
1499static int
1500xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1501{
1502 int t, sector;
1503
1504 /* p is used only to get the starting sector */
1505#if !defined (__alpha__)
1506 sector = (p ? get_start_sect(p) : 0);
1507#elif defined (__alpha__)
1508 sector = 0;
1509#endif
1510
Rob Landleyb73451d2006-02-24 16:29:00 +00001511 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1512 fdisk_fatal(unable_to_seek);
1513 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1514 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001515
Mike Frysinger1a540302006-04-16 05:58:21 +00001516 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1517 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001518
Rob Landleyb73451d2006-02-24 16:29:00 +00001519 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001520 return 0;
1521
Rob Landleyb73451d2006-02-24 16:29:00 +00001522 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1523 d->d_partitions[t].p_size = 0;
1524 d->d_partitions[t].p_offset = 0;
1525 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001526 }
1527
Rob Landleyb73451d2006-02-24 16:29:00 +00001528 if (d->d_npartitions > BSD_MAXPARTITIONS)
1529 fprintf(stderr, _("Warning: too many partitions "
1530 "(%d, maximum is %d).\n"),
1531 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001532 return 1;
1533}
1534
1535static int
1536xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1537{
Rob Landleyb73451d2006-02-24 16:29:00 +00001538 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001539
1540#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001541 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001542#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001543 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001544#endif
1545
Rob Landleyb73451d2006-02-24 16:29:00 +00001546 d->d_checksum = 0;
1547 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001548
Rob Landleyb73451d2006-02-24 16:29:00 +00001549 /* This is necessary if we want to write the bootstrap later,
1550 otherwise we'd write the old disklabel with the bootstrap.
1551 */
Mike Frysinger1a540302006-04-16 05:58:21 +00001552 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1553 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001554
1555#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001556 alpha_bootblock_checksum (disklabelbuffer);
1557 if (lseek(fd, 0, SEEK_SET) == -1)
1558 fdisk_fatal(unable_to_seek);
1559 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1560 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001561#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001562 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1563 fdisk_fatal(unable_to_seek);
1564 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1565 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001566#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001567 sync_disks();
1568 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001569}
1570
1571
1572#if !defined (__alpha__)
1573static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001574xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001575{
Rob Landleyb73451d2006-02-24 16:29:00 +00001576 switch (linux_type) {
1577 case 0x01: /* DOS 12-bit FAT */
1578 case 0x04: /* DOS 16-bit <32M */
1579 case 0x06: /* DOS 16-bit >=32M */
1580 case 0xe1: /* DOS access */
1581 case 0xe3: /* DOS R/O */
1582 case 0xf2: /* DOS secondary */
1583 return BSD_FS_MSDOS;
1584 case 0x07: /* OS/2 HPFS */
1585 return BSD_FS_HPFS;
1586 default:
1587 return BSD_FS_OTHER;
1588 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001589}
1590
1591static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001592xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001593{
Rob Landleyb73451d2006-02-24 16:29:00 +00001594 int k, i;
1595 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001596
Rob Landleyb73451d2006-02-24 16:29:00 +00001597 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001598
Rob Landleyb73451d2006-02-24 16:29:00 +00001599 if (!xbsd_check_new_partition(&i))
1600 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001601
Rob Landleyb73451d2006-02-24 16:29:00 +00001602 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001603
Rob Landleyb73451d2006-02-24 16:29:00 +00001604 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1605 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1606 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001607}
1608#endif
1609
1610#if defined (__alpha__)
1611
1612#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001613typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001614#endif
1615
1616static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001617alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001618{
Rob Landleyb73451d2006-02-24 16:29:00 +00001619 uint64_t *dp, sum;
1620 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001621
Rob Landleyb73451d2006-02-24 16:29:00 +00001622 dp = (uint64_t *)boot;
1623 sum = 0;
1624 for (i = 0; i < 63; i++)
1625 sum += dp[i];
1626 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001627}
1628#endif /* __alpha__ */
1629
1630#endif /* OSF_LABEL */
1631
1632#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley88621d72006-08-29 19:41:06 +00001633static unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001634__swap16(unsigned short x)
1635{
Eric Andersenacd244a2002-12-11 03:49:33 +00001636 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001637}
1638
Rob Landley88621d72006-08-29 19:41:06 +00001639static uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001640__swap32(uint32_t x)
1641{
1642 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001643 ((x & 0xFF00) << 8) |
1644 ((x & 0xFF0000) >> 8) |
1645 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001646}
1647#endif
1648
1649#ifdef CONFIG_FEATURE_SGI_LABEL
1650/*
1651 *
1652 * fdisksgilabel.c
1653 *
1654 * Copyright (C) Andreas Neuper, Sep 1998.
1655 * This file may be modified and redistributed under
1656 * the terms of the GNU Public License.
1657 *
1658 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1659 * Internationalization
1660 */
1661
1662
Rob Landleyb73451d2006-02-24 16:29:00 +00001663static int sgi_other_endian;
1664static int debug;
1665static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001666
1667/*
1668 * only dealing with free blocks here
1669 */
1670
Rob Landleyb73451d2006-02-24 16:29:00 +00001671typedef struct {
1672 unsigned int first;
1673 unsigned int last;
1674} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001675static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1676
1677static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001678setfreelist(int i, unsigned int f, unsigned int l)
1679{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001680 freelist[i].first = f;
1681 freelist[i].last = l;
1682}
1683
1684static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001685add2freelist(unsigned int f, unsigned int l)
1686{
1687 int i;
1688 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001689 if (freelist[i].last == 0)
1690 break;
1691 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001692}
1693
1694static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001695clearfreelist(void)
1696{
Eric Andersen040f4402003-07-30 08:40:37 +00001697 int i;
1698
1699 for (i = 0; i < 17 ; i++)
1700 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001701}
1702
Eric Andersen040f4402003-07-30 08:40:37 +00001703static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001704isinfreelist(unsigned int b)
1705{
Eric Andersen040f4402003-07-30 08:40:37 +00001706 int i;
1707
1708 for (i = 0; i < 17 ; i++)
1709 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001710 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001711 return 0;
1712}
1713 /* return last vacant block of this stride (never 0). */
1714 /* the '>=' is not quite correct, but simplifies the code */
1715/*
1716 * end of free blocks section
1717 */
1718
1719static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001720/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1721/* 0x01 */ { "\x01" "SGI trkrepl" },
1722/* 0x02 */ { "\x02" "SGI secrepl" },
1723/* SGI_SWAP */ { "\x03" "SGI raw" },
1724/* 0x04 */ { "\x04" "SGI bsd" },
1725/* 0x05 */ { "\x05" "SGI sysv" },
1726/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1727/* SGI_EFS */ { "\x07" "SGI efs" },
1728/* 0x08 */ { "\x08" "SGI lvol" },
1729/* 0x09 */ { "\x09" "SGI rlvol" },
1730/* SGI_XFS */ { "\x0a" "SGI xfs" },
1731/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1732/* SGI_XLV */ { "\x0c" "SGI xlv" },
1733/* SGI_XVM */ { "\x0d" "SGI xvm" },
1734/* LINUX_SWAP */ { "\x82" "Linux swap" },
1735/* LINUX_NATIVE */ { "\x83" "Linux native" },
1736/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1737/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1738 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001739};
1740
1741
1742static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001743sgi_get_nsect(void)
1744{
1745 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001746}
1747
1748static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001749sgi_get_ntrks(void)
1750{
1751 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001752}
1753
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001754static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001755two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1756{
1757 int i = 0;
1758 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001759
Rob Landleyb73451d2006-02-24 16:29:00 +00001760 size /= sizeof(unsigned int);
1761 for (i = 0; i < size; i++)
1762 sum -= SGI_SSWAP32(base[i]);
1763 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001764}
1765
1766static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001767check_sgi_label(void)
1768{
1769 if (sizeof(sgilabel) > 512) {
1770 fprintf(stderr,
1771 _("According to MIPS Computer Systems, Inc the "
1772 "Label must not contain more than 512 bytes\n"));
1773 exit(1);
1774 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001775
Rob Landleyb73451d2006-02-24 16:29:00 +00001776 if (sgilabel->magic != SGI_LABEL_MAGIC
1777 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001778 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001779 return 0;
1780 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001781
Rob Landleyb73451d2006-02-24 16:29:00 +00001782 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1783 /*
1784 * test for correct checksum
1785 */
1786 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1787 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001788 fprintf(stderr,
1789 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001790 }
1791 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001792 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001793 partitions = 16;
1794 sgi_volumes = 15;
1795 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001796}
1797
Eric Andersen040f4402003-07-30 08:40:37 +00001798static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001799sgi_get_start_sector(int i)
1800{
1801 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001802}
1803
Eric Andersen040f4402003-07-30 08:40:37 +00001804static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001805sgi_get_num_sectors(int i)
1806{
1807 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001808}
1809
1810static int
Eric Andersen040f4402003-07-30 08:40:37 +00001811sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001812{
Rob Landleyb73451d2006-02-24 16:29:00 +00001813 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001814}
1815
1816static int
1817sgi_get_bootpartition(void)
1818{
Rob Landleyb73451d2006-02-24 16:29:00 +00001819 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001820}
1821
1822static int
1823sgi_get_swappartition(void)
1824{
Rob Landleyb73451d2006-02-24 16:29:00 +00001825 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001826}
1827
1828static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001829sgi_list_table(int xtra)
1830{
1831 int i, w, wd;
1832 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001833
Rob Landleyb73451d2006-02-24 16:29:00 +00001834 if(xtra) {
1835 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1836 "%d cylinders, %d physical cylinders\n"
1837 "%d extra sects/cyl, interleave %d:1\n"
1838 "%s\n"
1839 "Units = %s of %d * 512 bytes\n\n"),
1840 disk_device, heads, sectors, cylinders,
1841 SGI_SSWAP16(sgiparam.pcylcount),
1842 SGI_SSWAP16(sgiparam.sparecyl),
1843 SGI_SSWAP16(sgiparam.ilfact),
1844 (char *)sgilabel,
1845 str_units(PLURAL), units_per_sector);
1846 } else {
1847 printf( _("\nDisk %s (SGI disk label): "
1848 "%d heads, %d sectors, %d cylinders\n"
1849 "Units = %s of %d * 512 bytes\n\n"),
1850 disk_device, heads, sectors, cylinders,
1851 str_units(PLURAL), units_per_sector );
1852 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001853
Rob Landleyb73451d2006-02-24 16:29:00 +00001854 w = strlen(disk_device);
1855 wd = strlen(_("Device"));
1856 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001857 w = wd;
1858
Rob Landleyb73451d2006-02-24 16:29:00 +00001859 printf(_("----- partitions -----\n"
1860 "Pt# %*s Info Start End Sectors Id System\n"),
1861 w + 2, _("Device"));
1862 for (i = 0 ; i < partitions; i++) {
1863 if( sgi_get_num_sectors(i) || debug ) {
1864 uint32_t start = sgi_get_start_sector(i);
1865 uint32_t len = sgi_get_num_sectors(i);
1866 kpi++; /* only count nonempty partitions */
1867 printf(
1868 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1869/* fdisk part number */ i+1,
1870/* device */ partname(disk_device, kpi, w+3),
1871/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1872/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1873/* start */ (long) scround(start),
1874/* end */ (long) scround(start+len)-1,
1875/* no odd flag on end */(long) len,
1876/* type id */ sgi_get_sysid(i),
1877/* type name */ partition_type(sgi_get_sysid(i)));
1878 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001879 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001880 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1881 "----- Directory Entries -----\n"),
1882 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001883 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001884 if (sgilabel->directory[i].vol_file_size) {
1885 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1886 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1887 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001888
Rob Landleyb73451d2006-02-24 16:29:00 +00001889 printf(_("%2d: %-10s sector%5u size%8u\n"),
1890 i, (char*)name, (unsigned int) start, (unsigned int) len);
1891 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001892 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001893}
1894
1895static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001896sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001897{
Rob Landleyb73451d2006-02-24 16:29:00 +00001898 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001899}
1900
Eric Andersen040f4402003-07-30 08:40:37 +00001901static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001902sgi_get_lastblock(void)
1903{
1904 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001905}
1906
1907static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001908sgi_set_swappartition(int i)
1909{
1910 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001911}
1912
1913static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001914sgi_check_bootfile(const char* aFile)
1915{
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001916 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1917 printf(_("\nInvalid Bootfile!\n"
1918 "\tThe bootfile must be an absolute non-zero pathname,\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00001919 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1920 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001921 } else {
1922 if (strlen(aFile) > 16) {
1923 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001924 "16 bytes maximum.\n"));
1925 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001926 } else {
1927 if (aFile[0] != '/') {
1928 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001929 "fully qualified pathname.\n"));
1930 return 0;
1931 }
Eric Andersen040f4402003-07-30 08:40:37 +00001932 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001933 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001934 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001935 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1936 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001937 /* filename is correct and did change */
1938 return 1;
1939 }
1940 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001941}
1942
1943static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001944sgi_get_bootfile(void)
1945{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001946 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001947}
1948
1949static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001950sgi_set_bootfile(const char* aFile)
1951{
1952 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001953
Rob Landleyb73451d2006-02-24 16:29:00 +00001954 if (sgi_check_bootfile(aFile)) {
1955 while (i < 16) {
1956 if ((aFile[i] != '\n') /* in principle caught again by next line */
1957 && (strlen(aFile) > i))
1958 sgilabel->boot_file[i] = aFile[i];
1959 else
1960 sgilabel->boot_file[i] = 0;
1961 i++;
1962 }
1963 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001964 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001965}
1966
1967static void
1968create_sgiinfo(void)
1969{
Rob Landleyb73451d2006-02-24 16:29:00 +00001970 /* I keep SGI's habit to write the sgilabel to the second block */
1971 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1972 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
Rob Landley11c7a7b2006-06-25 22:39:24 +00001973 strcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001974}
1975
Eric Andersen040f4402003-07-30 08:40:37 +00001976static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001977
1978static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001979sgi_write_table(void)
1980{
1981 sgilabel->csum = 0;
1982 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1983 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1984 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00001985 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00001986
1987 if (lseek(fd, 0, SEEK_SET) < 0)
1988 fdisk_fatal(unable_to_seek);
1989 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1990 fdisk_fatal(unable_to_write);
1991 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
1992 /*
1993 * keep this habit of first writing the "sgilabel".
1994 * I never tested whether it works without (AN 981002).
1995 */
1996 sgiinfo *info = fill_sgiinfo();
1997 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
1998 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
1999 fdisk_fatal(unable_to_seek);
2000 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2001 fdisk_fatal(unable_to_write);
2002 free(info);
2003 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002004}
2005
2006static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002007compare_start(int *x, int *y)
2008{
2009 /*
2010 * sort according to start sectors
2011 * and prefers largest partition:
2012 * entry zero is entire disk entry
2013 */
2014 unsigned int i = *x;
2015 unsigned int j = *y;
2016 unsigned int a = sgi_get_start_sector(i);
2017 unsigned int b = sgi_get_start_sector(j);
2018 unsigned int c = sgi_get_num_sectors(i);
2019 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002020
Rob Landleyb73451d2006-02-24 16:29:00 +00002021 if (a == b)
2022 return (d > c) ? 1 : (d == c) ? 0 : -1;
2023 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002024}
2025
2026
2027static int
Eric Andersen040f4402003-07-30 08:40:37 +00002028verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002029{
Rob Landleyb73451d2006-02-24 16:29:00 +00002030 int Index[16]; /* list of valid partitions */
2031 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2032 int entire = 0, i = 0;
2033 unsigned int start = 0;
2034 long long gap = 0; /* count unused blocks */
2035 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002036
Rob Landleyb73451d2006-02-24 16:29:00 +00002037 clearfreelist();
2038 for (i = 0; i < 16; i++) {
2039 if (sgi_get_num_sectors(i) != 0) {
2040 Index[sortcount++] = i;
2041 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2042 if (entire++ == 1) {
2043 if (verbose)
2044 printf(_("More than one entire disk entry present.\n"));
2045 }
2046 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002047 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002048 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002049 if (sortcount == 0) {
2050 if (verbose)
2051 printf(_("No partitions defined\n"));
2052 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2053 }
2054 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2055 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2056 if ((Index[0] != 10) && verbose)
2057 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2058 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2059 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002060 "at block 0,\n"
2061 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002062 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002063 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002064 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2065 printf(_("The entire disk partition is only %d diskblock large,\n"
2066 "but the disk is %d diskblocks long.\n"),
2067 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002068 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002069 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002070 if (verbose)
2071 printf(_("One Partition (#11) should cover the entire disk.\n"));
2072 if (debug > 2)
2073 printf("sysid=%d\tpartition=%d\n",
2074 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002075 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002076 for (i = 1, start = 0; i < sortcount; i++) {
2077 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2078
2079 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2080 if (debug) /* I do not understand how some disks fulfil it */
2081 if (verbose)
2082 printf(_("Partition %d does not start on cylinder boundary.\n"),
2083 Index[i]+1);
2084 }
2085 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2086 if (debug) /* I do not understand how some disks fulfil it */
2087 if (verbose)
2088 printf(_("Partition %d does not end on cylinder boundary.\n"),
2089 Index[i]+1);
2090 }
2091 /* We cannot handle several "entire disk" entries. */
2092 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2093 if (start > sgi_get_start_sector(Index[i])) {
2094 if (verbose)
2095 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2096 Index[i-1]+1, Index[i]+1,
2097 start - sgi_get_start_sector(Index[i]));
2098 if (gap > 0) gap = -gap;
2099 if (gap == 0) gap = -1;
2100 }
2101 if (start < sgi_get_start_sector(Index[i])) {
2102 if (verbose)
2103 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2104 sgi_get_start_sector(Index[i]) - start,
2105 start, sgi_get_start_sector(Index[i])-1);
2106 gap += sgi_get_start_sector(Index[i]) - start;
2107 add2freelist(start, sgi_get_start_sector(Index[i]));
2108 }
2109 start = sgi_get_start_sector(Index[i])
2110 + sgi_get_num_sectors(Index[i]);
2111 if (debug > 1) {
2112 if (verbose)
2113 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2114 sgi_get_start_sector(Index[i]),
2115 sgi_get_num_sectors(Index[i]),
2116 sgi_get_sysid(Index[i]));
2117 }
2118 }
2119 if (start < lastblock) {
2120 if (verbose)
2121 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2122 lastblock - start, start, lastblock-1);
2123 gap += lastblock - start;
2124 add2freelist(start, lastblock);
2125 }
2126 /*
2127 * Done with arithmetics
2128 * Go for details now
2129 */
2130 if (verbose) {
2131 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2132 printf(_("\nThe boot partition does not exist.\n"));
2133 }
2134 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2135 printf(_("\nThe swap partition does not exist.\n"));
2136 } else {
2137 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2138 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2139 printf(_("\nThe swap partition has no swap type.\n"));
2140 }
2141 if (sgi_check_bootfile("/unix"))
2142 printf(_("\tYou have chosen an unusual boot file name.\n"));
2143 }
2144 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002145}
2146
2147static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002148sgi_gaps(void)
2149{
2150 /*
2151 * returned value is:
2152 * = 0 : disk is properly filled to the rim
2153 * < 0 : there is an overlap
2154 * > 0 : there is still some vacant space
2155 */
2156 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002157}
2158
2159static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002160sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002161{
Rob Landleyb73451d2006-02-24 16:29:00 +00002162 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2163 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2164 return;
2165 }
2166 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2167 && (sgi_get_start_sector(i) < 1) ) {
2168 read_chars(
2169 _("It is highly recommended that the partition at offset 0\n"
2170 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2171 "retrieve from its directory standalone tools like sash and fx.\n"
2172 "Only the \"SGI volume\" entire disk section may violate this.\n"
2173 "Type YES if you are sure about tagging this partition differently.\n"));
2174 if (strcmp(line_ptr, _("YES\n")))
2175 return;
2176 }
2177 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002178}
2179
2180/* returns partition index of first entry marked as entire disk */
2181static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002182sgi_entire(void)
2183{
2184 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002185
Rob Landleyb73451d2006-02-24 16:29:00 +00002186 for (i = 0; i < 16; i++)
2187 if (sgi_get_sysid(i) == SGI_VOLUME)
2188 return i;
2189 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002190}
2191
2192static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002193sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2194{
2195 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2196 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2197 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2198 set_changed(i);
2199 if (sgi_gaps() < 0) /* rebuild freelist */
2200 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002201}
2202
2203static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002204sgi_set_entire(void)
2205{
2206 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002207
Rob Landleyb73451d2006-02-24 16:29:00 +00002208 for (n = 10; n < partitions; n++) {
2209 if(!sgi_get_num_sectors(n) ) {
2210 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2211 break;
2212 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002213 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002214}
2215
2216static void
2217sgi_set_volhdr(void)
2218{
Rob Landleyb73451d2006-02-24 16:29:00 +00002219 int n;
2220
2221 for (n = 8; n < partitions; n++) {
2222 if (!sgi_get_num_sectors(n)) {
2223 /*
2224 * 5 cylinders is an arbitrary value I like
2225 * IRIX 5.3 stored files in the volume header
2226 * (like sash, symmon, fx, ide) with ca. 3200
2227 * sectors.
2228 */
2229 if (heads * sectors * 5 < sgi_get_lastblock())
2230 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2231 break;
2232 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002233 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002234}
2235
2236static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002237sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002238{
Rob Landleyb73451d2006-02-24 16:29:00 +00002239 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002240}
2241
2242static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002243sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002244{
Rob Landleyb73451d2006-02-24 16:29:00 +00002245 char mesg[256];
2246 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002247
Rob Landleyb73451d2006-02-24 16:29:00 +00002248 if (n == 10) {
2249 sys = SGI_VOLUME;
2250 } else if (n == 8) {
2251 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002252 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002253 if(sgi_get_num_sectors(n)) {
2254 printf(_("Partition %d is already defined. Delete "
2255 "it before re-adding it.\n"), n + 1);
2256 return;
2257 }
2258 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2259 printf(_("Attempting to generate entire disk entry automatically.\n"));
2260 sgi_set_entire();
2261 sgi_set_volhdr();
2262 }
2263 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2264 printf(_("The entire disk is already covered with partitions.\n"));
2265 return;
2266 }
2267 if (sgi_gaps() < 0) {
2268 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2269 return;
2270 }
2271 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2272 while (1) {
2273 if(sys == SGI_VOLUME) {
2274 last = sgi_get_lastblock();
2275 first = read_int(0, 0, last-1, 0, mesg);
2276 if (first != 0) {
2277 printf(_("It is highly recommended that eleventh partition\n"
2278 "covers the entire disk and is of type `SGI volume'\n"));
2279 }
2280 } else {
2281 first = freelist[0].first;
2282 last = freelist[0].last;
2283 first = read_int(scround(first), scround(first), scround(last)-1,
2284 0, mesg);
2285 }
2286 if (display_in_cyl_units)
2287 first *= units_per_sector;
2288 else
2289 first = first; /* align to cylinder if you know how ... */
2290 if(!last )
2291 last = isinfreelist(first);
2292 if(last == 0) {
2293 printf(_("You will get a partition overlap on the disk. "
2294 "Fix it first!\n"));
2295 } else
2296 break;
2297 }
2298 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2299 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2300 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002301 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002302 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002303 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002304 last = last; /* align to cylinder if You know how ... */
2305 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2306 printf(_("It is highly recommended that eleventh partition\n"
2307 "covers the entire disk and is of type `SGI volume'\n"));
2308 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002309}
2310
Eric Andersen040f4402003-07-30 08:40:37 +00002311#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002312static void
2313create_sgilabel(void)
2314{
Rob Landleyb73451d2006-02-24 16:29:00 +00002315 struct hd_geometry geometry;
2316 struct {
2317 unsigned int start;
2318 unsigned int nsect;
2319 int sysid;
2320 } old[4];
2321 int i = 0;
2322 long longsectors; /* the number of sectors on the device */
2323 int res; /* the result from the ioctl */
2324 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002325
Rob Landleyb73451d2006-02-24 16:29:00 +00002326 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002327
Rob Landleyb73451d2006-02-24 16:29:00 +00002328 fprintf( stderr,
2329 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2330 "until you decide to write them. After that, of course, the previous\n"
2331 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002332
Rob Landley2c39eee2006-05-05 16:54:40 +00002333 sgi_other_endian = (BB_LITTLE_ENDIAN);
Rob Landleyb73451d2006-02-24 16:29:00 +00002334 res = ioctl(fd, BLKGETSIZE, &longsectors);
2335 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2336 heads = geometry.heads;
2337 sectors = geometry.sectors;
2338 if (res == 0) {
2339 /* the get device size ioctl was successful */
2340 cylinders = longsectors / (heads * sectors);
2341 cylinders /= sec_fac;
2342 } else {
2343 /* otherwise print error and use truncated version */
2344 cylinders = geometry.cylinders;
2345 fprintf(stderr,
2346 _("Warning: BLKGETSIZE ioctl failed on %s. "
2347 "Using geometry cylinder value of %d.\n"
2348 "This value may be truncated for devices"
2349 " > 33.8 GB.\n"), disk_device, cylinders);
2350 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002351 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002352 for (i = 0; i < 4; i++) {
2353 old[i].sysid = 0;
2354 if (valid_part_table_flag(MBRbuffer)) {
2355 if(get_part_table(i)->sys_ind) {
2356 old[i].sysid = get_part_table(i)->sys_ind;
2357 old[i].start = get_start_sect(get_part_table(i));
2358 old[i].nsect = get_nr_sects(get_part_table(i));
2359 printf(_("Trying to keep parameters of partition %d.\n"), i);
2360 if (debug)
2361 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2362 old[i].sysid, old[i].start, old[i].nsect);
2363 }
2364 }
2365 }
Eric Andersen040f4402003-07-30 08:40:37 +00002366
Rob Landleyb73451d2006-02-24 16:29:00 +00002367 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2368 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2369 sgilabel->boot_part = SGI_SSWAP16(0);
2370 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002371
Rob Landleyb73451d2006-02-24 16:29:00 +00002372 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2373 memset(sgilabel->boot_file, 0, 16);
2374 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002375
Rob Landleyb73451d2006-02-24 16:29:00 +00002376 sgilabel->devparam.skew = (0);
2377 sgilabel->devparam.gap1 = (0);
2378 sgilabel->devparam.gap2 = (0);
2379 sgilabel->devparam.sparecyl = (0);
2380 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2381 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2382 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002383 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002384 sgilabel->devparam.cmd_tag_queue_depth = (0);
2385 sgilabel->devparam.unused0 = (0);
2386 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2387 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002388 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002389 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2390 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2391 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002392 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002393 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2394 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2395 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2396 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2397 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2398 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2399 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2400 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2401 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2402 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2403 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002404 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002405 partitions = 16;
2406 sgi_volumes = 15;
2407 sgi_set_entire();
2408 sgi_set_volhdr();
2409 for (i = 0; i < 4; i++) {
2410 if(old[i].sysid) {
2411 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2412 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002413 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002414}
2415
2416static void
2417sgi_set_xcyl(void)
2418{
Rob Landleyb73451d2006-02-24 16:29:00 +00002419 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002420}
Eric Andersen040f4402003-07-30 08:40:37 +00002421#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002422
2423/* _____________________________________________________________
2424 */
2425
Eric Andersen040f4402003-07-30 08:40:37 +00002426static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002427fill_sgiinfo(void)
2428{
Rob Landleyb73451d2006-02-24 16:29:00 +00002429 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002430
Rob Landleyb73451d2006-02-24 16:29:00 +00002431 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2432 info->b1 = SGI_SSWAP32(-1);
2433 info->b2 = SGI_SSWAP16(-1);
2434 info->b3 = SGI_SSWAP16(1);
2435 /* You may want to replace this string !!!!!!! */
2436 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2437 strcpy( (char*)info->serial, "0000" );
2438 info->check1816 = SGI_SSWAP16(18*256 +16 );
2439 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2440 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002441}
2442#endif /* SGI_LABEL */
2443
2444
2445#ifdef CONFIG_FEATURE_SUN_LABEL
2446/*
2447 * fdisksunlabel.c
2448 *
2449 * I think this is mostly, or entirely, due to
2450 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2451 *
2452 * Merged with fdisk for other architectures, aeb, June 1998.
2453 *
2454 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2455 * Internationalization
2456 */
2457
2458
Rob Landleyb73451d2006-02-24 16:29:00 +00002459static int sun_other_endian;
2460static int scsi_disk;
2461static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002462
2463#ifndef IDE0_MAJOR
2464#define IDE0_MAJOR 3
2465#endif
2466#ifndef IDE1_MAJOR
2467#define IDE1_MAJOR 22
2468#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002469
Rob Landleyb73451d2006-02-24 16:29:00 +00002470static void
2471guess_device_type(void)
2472{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002473 struct stat bootstat;
2474
Rob Landleyb73451d2006-02-24 16:29:00 +00002475 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002476 scsi_disk = 0;
2477 floppy = 0;
2478 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002479 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2480 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002481 scsi_disk = 0;
2482 floppy = 0;
2483 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002484 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002485 scsi_disk = 0;
2486 floppy = 1;
2487 } else {
2488 scsi_disk = 1;
2489 floppy = 0;
2490 }
2491}
2492
2493static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002494 { "\x00" "Empty" }, /* 0 */
2495 { "\x01" "Boot" }, /* 1 */
2496 { "\x02" "SunOS root" }, /* 2 */
2497 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2498 { "\x04" "SunOS usr" }, /* 4 */
2499 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2500 { "\x06" "SunOS stand" }, /* 6 */
2501 { "\x07" "SunOS var" }, /* 7 */
2502 { "\x08" "SunOS home" }, /* 8 */
2503 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2504 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2505 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002506/* New (2.2.x) raid partition with autodetect using persistent superblock */
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002507 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
Rob Landleyb73451d2006-02-24 16:29:00 +00002508 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002509};
2510
2511
2512static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002513set_sun_partition(int i, uint start, uint stop, int sysid)
2514{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002515 sunlabel->infos[i].id = sysid;
2516 sunlabel->partitions[i].start_cylinder =
2517 SUN_SSWAP32(start / (heads * sectors));
2518 sunlabel->partitions[i].num_sectors =
2519 SUN_SSWAP32(stop - start);
2520 set_changed(i);
2521}
2522
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002523static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002524check_sun_label(void)
2525{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002526 unsigned short *ush;
2527 int csum;
2528
Rob Landleyb73451d2006-02-24 16:29:00 +00002529 if (sunlabel->magic != SUN_LABEL_MAGIC
2530 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002531 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002532 sun_other_endian = 0;
2533 return 0;
2534 }
2535 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2536 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2537 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2538 if (csum) {
2539 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2540 "Probably you'll have to set all the values,\n"
2541 "e.g. heads, sectors, cylinders and partitions\n"
2542 "or force a fresh label (s command in main menu)\n"));
2543 } else {
2544 heads = SUN_SSWAP16(sunlabel->ntrks);
2545 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2546 sectors = SUN_SSWAP16(sunlabel->nsect);
2547 }
2548 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002549 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002550 partitions = 8;
2551 return 1;
2552}
2553
2554static const struct sun_predefined_drives {
2555 const char *vendor;
2556 const char *model;
2557 unsigned short sparecyl;
2558 unsigned short ncyl;
2559 unsigned short nacyl;
2560 unsigned short pcylcount;
2561 unsigned short ntrks;
2562 unsigned short nsect;
2563 unsigned short rspeed;
2564} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002565 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2566 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2567 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2568 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2569 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2570 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2571 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2572 { "","SUN0104",1,974,2,1019,6,35,3662},
2573 { "","SUN0207",4,1254,2,1272,9,36,3600},
2574 { "","SUN0327",3,1545,2,1549,9,46,3600},
2575 { "","SUN0340",0,1538,2,1544,6,72,4200},
2576 { "","SUN0424",2,1151,2,2500,9,80,4400},
2577 { "","SUN0535",0,1866,2,2500,7,80,5400},
2578 { "","SUN0669",5,1614,2,1632,15,54,3600},
2579 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2580 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2581 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2582 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2583 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002584};
2585
2586static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002587sun_autoconfigure_scsi(void)
2588{
2589 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002590
2591#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002592 unsigned int id[2];
2593 char buffer[2048];
2594 char buffer2[2048];
2595 FILE *pfd;
2596 char *vendor;
2597 char *model;
2598 char *q;
2599 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002600
Rob Landleyb73451d2006-02-24 16:29:00 +00002601 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2602 sprintf(buffer,
2603 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00002604 /* This is very wrong (works only if you have one HBA),
2605 but I haven't found a way how to get hostno
2606 from the current kernel */
2607 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00002608 (id[0]>>16) & 0xff,
2609 id[0] & 0xff,
2610 (id[0]>>8) & 0xff
2611 );
2612 pfd = fopen("/proc/scsi/scsi","r");
2613 if (pfd) {
2614 while (fgets(buffer2, 2048, pfd)) {
2615 if (!strcmp(buffer, buffer2)) {
2616 if (fgets(buffer2,2048,pfd)) {
2617 q = strstr(buffer2,"Vendor: ");
2618 if (q) {
2619 q += 8;
2620 vendor = q;
2621 q = strstr(q," ");
2622 *q++ = 0; /* truncate vendor name */
2623 q = strstr(q,"Model: ");
2624 if (q) {
2625 *q = 0;
2626 q += 7;
2627 model = q;
2628 q = strstr(q," Rev: ");
2629 if (q) {
2630 *q = 0;
2631 for (i = 0; i < SIZE(sun_drives); i++) {
2632 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2633 continue;
2634 if (!strstr(model, sun_drives[i].model))
2635 continue;
2636 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2637 p = sun_drives + i;
2638 break;
2639 }
2640 }
2641 }
2642 }
2643 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002644 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002645 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002646 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002647 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002648 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002649 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002650#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002651 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002652}
2653
Rob Landleyb73451d2006-02-24 16:29:00 +00002654static void
2655create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002656{
2657 struct hd_geometry geometry;
2658 unsigned int ndiv;
2659 int i;
2660 unsigned char c;
2661 const struct sun_predefined_drives *p = NULL;
2662
2663 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002664 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2665 "until you decide to write them. After that, of course, the previous\n"
2666 "content won't be recoverable.\n\n"));
Rob Landley2c39eee2006-05-05 16:54:40 +00002667 sun_other_endian = BB_LITTLE_ENDIAN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002668 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2669 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2670 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002671 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002672 " ? auto configure\n"
2673 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002674 for (i = 0; i < SIZE(sun_drives); i++) {
2675 printf(" %c %s%s%s\n",
2676 i + 'a', sun_drives[i].vendor,
2677 (*sun_drives[i].vendor) ? " " : "",
2678 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002679 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002680 while (1) {
2681 c = read_char(_("Select type (? for auto, 0 for custom): "));
2682 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2683 p = sun_drives + c - 'a';
2684 break;
2685 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2686 p = sun_drives + c - 'A';
2687 break;
2688 } else if (c == '0') {
2689 break;
2690 } else if (c == '?' && scsi_disk) {
2691 p = sun_autoconfigure_scsi();
2692 if (!p)
2693 printf(_("Autoconfigure failed.\n"));
2694 else
2695 break;
2696 }
2697 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002698 }
2699 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002700 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2701 heads = geometry.heads;
2702 sectors = geometry.sectors;
2703 cylinders = geometry.cylinders;
2704 } else {
2705 heads = 0;
2706 sectors = 0;
2707 cylinders = 0;
2708 }
2709 if (floppy) {
2710 sunlabel->nacyl = 0;
2711 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2712 sunlabel->rspeed = SUN_SSWAP16(300);
2713 sunlabel->ilfact = SUN_SSWAP16(1);
2714 sunlabel->sparecyl = 0;
2715 } else {
2716 heads = read_int(1,heads,1024,0,_("Heads"));
2717 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002718 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002719 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002720 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002721 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2722 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2723 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2724 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2725 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2726 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2727 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002728 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002729 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2730 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2731 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2732 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2733 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2734 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2735 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2736 sunlabel->ilfact = SUN_SSWAP16(1);
2737 cylinders = p->ncyl;
2738 heads = p->ntrks;
2739 sectors = p->nsect;
2740 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002741 }
2742
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002743 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002744 "%s%s%s cyl %d alt %d hd %d sec %d",
2745 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2746 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002747 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2748
2749 sunlabel->ntrks = SUN_SSWAP16(heads);
2750 sunlabel->nsect = SUN_SSWAP16(sectors);
2751 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2752 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002753 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002754 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002755 if (cylinders * heads * sectors >= 150 * 2048) {
2756 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2757 } else
2758 ndiv = cylinders * 2 / 3;
2759 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2760 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2761 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002762 }
2763 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2764 {
2765 unsigned short *ush = (unsigned short *)sunlabel;
2766 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002767 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002768 csum ^= *ush++;
2769 sunlabel->csum = csum;
2770 }
2771
2772 set_all_unchanged();
2773 set_changed(0);
2774 get_boot(create_empty_sun);
2775}
2776
2777static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002778toggle_sunflags(int i, unsigned char mask)
2779{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002780 if (sunlabel->infos[i].flags & mask)
2781 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002782 else
2783 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002784 set_changed(i);
2785}
2786
2787static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002788fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2789{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002790 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002791
2792 *start = 0;
2793 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002794 for (i = 0; i < partitions; i++) {
2795 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002796 && sunlabel->infos[i].id
2797 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002798 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2799 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2800 if (continuous) {
2801 if (starts[i] == *start)
2802 *start += lens[i];
2803 else if (starts[i] + lens[i] >= *stop)
2804 *stop = starts[i];
2805 else
2806 continuous = 0;
2807 /* There will be probably more gaps
2808 than one, so lets check afterwards */
2809 }
2810 } else {
2811 starts[i] = 0;
2812 lens[i] = 0;
2813 }
2814 }
2815}
2816
2817static uint *verify_sun_starts;
2818
2819static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002820verify_sun_cmp(int *a, int *b)
2821{
2822 if (*a == -1) return 1;
2823 if (*b == -1) return -1;
2824 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2825 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002826}
2827
2828static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002829verify_sun(void)
2830{
2831 uint starts[8], lens[8], start, stop;
2832 int i,j,k,starto,endo;
2833 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002834
Rob Landleyb73451d2006-02-24 16:29:00 +00002835 verify_sun_starts = starts;
2836 fetch_sun(starts,lens,&start,&stop);
2837 for (k = 0; k < 7; k++) {
2838 for (i = 0; i < 8; i++) {
2839 if (k && (lens[i] % (heads * sectors))) {
2840 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002841 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002842 if (lens[i]) {
2843 for (j = 0; j < i; j++)
2844 if (lens[j]) {
2845 if (starts[j] == starts[i]+lens[i]) {
2846 starts[j] = starts[i]; lens[j] += lens[i];
2847 lens[i] = 0;
2848 } else if (starts[i] == starts[j]+lens[j]){
2849 lens[j] += lens[i];
2850 lens[i] = 0;
2851 } else if (!k) {
2852 if (starts[i] < starts[j]+lens[j]
2853 && starts[j] < starts[i]+lens[i]) {
2854 starto = starts[i];
2855 if (starts[j] > starto)
2856 starto = starts[j];
2857 endo = starts[i]+lens[i];
2858 if (starts[j]+lens[j] < endo)
2859 endo = starts[j]+lens[j];
2860 printf(_("Partition %d overlaps with others in "
2861 "sectors %d-%d\n"), i+1, starto, endo);
2862 }
2863 }
2864 }
2865 }
2866 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002867 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002868 for (i = 0; i < 8; i++) {
2869 if (lens[i])
2870 array[i] = i;
2871 else
2872 array[i] = -1;
2873 }
2874 qsort(array,SIZE(array),sizeof(array[0]),
2875 (int (*)(const void *,const void *)) verify_sun_cmp);
2876 if (array[0] == -1) {
2877 printf(_("No partitions defined\n"));
2878 return;
2879 }
2880 stop = cylinders * heads * sectors;
2881 if (starts[array[0]])
2882 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2883 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2884 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2885 }
2886 start = starts[array[i]] + lens[array[i]];
2887 if (start < stop)
2888 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002889}
2890
2891static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002892add_sun_partition(int n, int sys)
2893{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002894 uint start, stop, stop2;
2895 uint starts[8], lens[8];
2896 int whole_disk = 0;
2897
2898 char mesg[256];
2899 int i, first, last;
2900
2901 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2902 printf(_("Partition %d is already defined. Delete "
2903 "it before re-adding it.\n"), n + 1);
2904 return;
2905 }
2906
2907 fetch_sun(starts,lens,&start,&stop);
2908 if (stop <= start) {
2909 if (n == 2)
2910 whole_disk = 1;
2911 else {
2912 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002913 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002914 return;
2915 }
2916 }
2917 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002918 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002919 if (whole_disk)
2920 first = read_int(0, 0, 0, 0, mesg);
2921 else
2922 first = read_int(scround(start), scround(stop)+1,
2923 scround(stop), 0, mesg);
2924 if (display_in_cyl_units)
2925 first *= units_per_sector;
2926 else
2927 /* Starting sector has to be properly aligned */
2928 first = (first + heads * sectors - 1) / (heads * sectors);
2929 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002930 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002931It is highly recommended that the third partition covers the whole disk\n\
2932and is of type `Whole disk'\n");
2933 /* ewt asks to add: "don't start a partition at cyl 0"
2934 However, edmundo@rano.demon.co.uk writes:
2935 "In addition to having a Sun partition table, to be able to
2936 boot from the disc, the first partition, /dev/sdX1, must
2937 start at cylinder 0. This means that /dev/sdX1 contains
2938 the partition table and the boot block, as these are the
2939 first two sectors of the disc. Therefore you must be
2940 careful what you use /dev/sdX1 for. In particular, you must
2941 not use a partition starting at cylinder 0 for Linux swap,
2942 as that would overwrite the partition table and the boot
2943 block. You may, however, use such a partition for a UFS
2944 or EXT2 file system, as these file systems leave the first
2945 1024 bytes undisturbed. */
2946 /* On the other hand, one should not use partitions
2947 starting at block 0 in an md, or the label will
2948 be trashed. */
2949 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002950 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002951 break;
2952 if (i < partitions && !whole_disk) {
2953 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002954 whole_disk = 1;
2955 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002956 }
2957 printf(_("Sector %d is already allocated\n"), first);
2958 } else
2959 break;
2960 }
2961 stop = cylinders * heads * sectors;
2962 stop2 = stop;
2963 for (i = 0; i < partitions; i++) {
2964 if (starts[i] > first && starts[i] < stop)
2965 stop = starts[i];
2966 }
2967 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002968 _("Last %s or +size or +sizeM or +sizeK"),
2969 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002970 if (whole_disk)
2971 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2972 0, mesg);
2973 else if (n == 2 && !first)
2974 last = read_int(scround(first), scround(stop2), scround(stop2),
2975 scround(first), mesg);
2976 else
2977 last = read_int(scround(first), scround(stop), scround(stop),
2978 scround(first), mesg);
2979 if (display_in_cyl_units)
2980 last *= units_per_sector;
2981 if (n == 2 && !first) {
2982 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002983 whole_disk = 1;
2984 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002985 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002986 printf(_("You haven't covered the whole disk with "
2987 "the 3rd partition, but your value\n"
2988 "%d %s covers some other partition. "
2989 "Your entry has been changed\n"
2990 "to %d %s\n"),
2991 scround(last), str_units(SINGULAR),
2992 scround(stop), str_units(SINGULAR));
2993 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002994 }
2995 } else if (!whole_disk && last > stop)
2996 last = stop;
2997
Rob Landleyb73451d2006-02-24 16:29:00 +00002998 if (whole_disk)
2999 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003000 set_sun_partition(n, first, last, sys);
3001}
3002
3003static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003004sun_delete_partition(int i)
3005{
Eric Andersen040f4402003-07-30 08:40:37 +00003006 unsigned int nsec;
3007
Rob Landleyb73451d2006-02-24 16:29:00 +00003008 if (i == 2
3009 && sunlabel->infos[i].id == WHOLE_DISK
3010 && !sunlabel->partitions[i].start_cylinder
3011 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003012 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003013 "consider leaving this\n"
3014 "partition as Whole disk (5), starting at 0, with %u "
3015 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003016 sunlabel->infos[i].id = 0;
3017 sunlabel->partitions[i].num_sectors = 0;
3018}
3019
3020static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003021sun_change_sysid(int i, int sys)
3022{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003023 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003024 read_chars(
3025 _("It is highly recommended that the partition at offset 0\n"
3026 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3027 "there may destroy your partition table and bootblock.\n"
3028 "Type YES if you're very sure you would like that partition\n"
3029 "tagged with 82 (Linux swap): "));
3030 if (strcmp (line_ptr, _("YES\n")))
3031 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003032 }
3033 switch (sys) {
3034 case SUNOS_SWAP:
3035 case LINUX_SWAP:
3036 /* swaps are not mountable by default */
3037 sunlabel->infos[i].flags |= 0x01;
3038 break;
3039 default:
3040 /* assume other types are mountable;
3041 user can change it anyway */
3042 sunlabel->infos[i].flags &= ~0x01;
3043 break;
3044 }
3045 sunlabel->infos[i].id = sys;
3046}
3047
3048static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003049sun_list_table(int xtra)
3050{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003051 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003052
3053 w = strlen(disk_device);
3054 if (xtra)
3055 printf(
3056 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3057 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3058 "%d extra sects/cyl, interleave %d:1\n"
3059 "%s\n"
3060 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003061 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3062 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3063 SUN_SSWAP16(sunlabel->pcylcount),
3064 SUN_SSWAP16(sunlabel->sparecyl),
3065 SUN_SSWAP16(sunlabel->ilfact),
3066 (char *)sunlabel,
3067 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003068 else
3069 printf(
3070 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3071 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003072 disk_device, heads, sectors, cylinders,
3073 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003074
3075 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003076 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003077 for (i = 0 ; i < partitions; i++) {
3078 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003079 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3080 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003081 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00003082 partname(disk_device, i+1, w), /* device */
3083 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3084 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3085 (long) scround(start), /* start */
3086 (long) scround(start+len), /* end */
3087 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3088 sunlabel->infos[i].id, /* type id */
3089 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003090 }
3091 }
3092}
3093
Eric Andersen040f4402003-07-30 08:40:37 +00003094#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3095
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003096static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003097sun_set_alt_cyl(void)
3098{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003099 sunlabel->nacyl =
3100 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003101 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003102}
3103
3104static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003105sun_set_ncyl(int cyl)
3106{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003107 sunlabel->ncyl = SUN_SSWAP16(cyl);
3108}
3109
3110static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003111sun_set_xcyl(void)
3112{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003113 sunlabel->sparecyl =
3114 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003115 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003116}
3117
3118static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003119sun_set_ilfact(void)
3120{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003121 sunlabel->ilfact =
3122 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003123 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003124}
3125
3126static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003127sun_set_rspeed(void)
3128{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003129 sunlabel->rspeed =
3130 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003131 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003132}
3133
3134static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003135sun_set_pcylcount(void)
3136{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003137 sunlabel->pcylcount =
3138 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003139 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003140}
Eric Andersen040f4402003-07-30 08:40:37 +00003141#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003142
3143static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003144sun_write_table(void)
3145{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003146 unsigned short *ush = (unsigned short *)sunlabel;
3147 unsigned short csum = 0;
3148
Rob Landleyb73451d2006-02-24 16:29:00 +00003149 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003150 csum ^= *ush++;
3151 sunlabel->csum = csum;
3152 if (lseek(fd, 0, SEEK_SET) < 0)
3153 fdisk_fatal(unable_to_seek);
3154 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3155 fdisk_fatal(unable_to_write);
3156}
3157#endif /* SUN_LABEL */
3158
3159/* DOS partition types */
3160
3161static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003162 { "\x00" "Empty" },
3163 { "\x01" "FAT12" },
3164 { "\x04" "FAT16 <32M" },
3165 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3166 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3167 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3168 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3169 { "\x0b" "Win95 FAT32" },
3170 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3171 { "\x0e" "Win95 FAT16 (LBA)" },
3172 { "\x0f" "Win95 Ext'd (LBA)" },
3173 { "\x11" "Hidden FAT12" },
3174 { "\x12" "Compaq diagnostics" },
3175 { "\x14" "Hidden FAT16 <32M" },
3176 { "\x16" "Hidden FAT16" },
3177 { "\x17" "Hidden HPFS/NTFS" },
3178 { "\x1b" "Hidden Win95 FAT32" },
3179 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3180 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3181 { "\x3c" "PartitionMagic recovery" },
3182 { "\x41" "PPC PReP Boot" },
3183 { "\x42" "SFS" },
3184 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3185 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3186 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3187 { "\x82" "Linux swap" }, /* also Solaris */
3188 { "\x83" "Linux" },
3189 { "\x84" "OS/2 hidden C: drive" },
3190 { "\x85" "Linux extended" },
3191 { "\x86" "NTFS volume set" },
3192 { "\x87" "NTFS volume set" },
3193 { "\x8e" "Linux LVM" },
3194 { "\x9f" "BSD/OS" }, /* BSDI */
3195 { "\xa0" "IBM Thinkpad hibernation" },
3196 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3197 { "\xa6" "OpenBSD" },
3198 { "\xa8" "Darwin UFS" },
3199 { "\xa9" "NetBSD" },
3200 { "\xab" "Darwin boot" },
3201 { "\xb7" "BSDI fs" },
3202 { "\xb8" "BSDI swap" },
3203 { "\xbe" "Solaris boot" },
3204 { "\xeb" "BeOS fs" },
3205 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3206 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3207 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3208 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3209 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3210 autodetect using persistent
3211 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003212#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003213 { "\x02" "XENIX root" },
3214 { "\x03" "XENIX usr" },
3215 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3216 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3217 { "\x10" "OPUS" },
3218 { "\x18" "AST SmartSleep" },
3219 { "\x24" "NEC DOS" },
3220 { "\x39" "Plan 9" },
3221 { "\x40" "Venix 80286" },
3222 { "\x4d" "QNX4.x" },
3223 { "\x4e" "QNX4.x 2nd part" },
3224 { "\x4f" "QNX4.x 3rd part" },
3225 { "\x50" "OnTrack DM" },
3226 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3227 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3228 { "\x53" "OnTrack DM6 Aux3" },
3229 { "\x54" "OnTrackDM6" },
3230 { "\x55" "EZ-Drive" },
3231 { "\x56" "Golden Bow" },
3232 { "\x5c" "Priam Edisk" },
3233 { "\x61" "SpeedStor" },
3234 { "\x64" "Novell Netware 286" },
3235 { "\x65" "Novell Netware 386" },
3236 { "\x70" "DiskSecure Multi-Boot" },
3237 { "\x75" "PC/IX" },
3238 { "\x93" "Amoeba" },
3239 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3240 { "\xa7" "NeXTSTEP" },
3241 { "\xbb" "Boot Wizard hidden" },
3242 { "\xc1" "DRDOS/sec (FAT-12)" },
3243 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3244 { "\xc6" "DRDOS/sec (FAT-16)" },
3245 { "\xc7" "Syrinx" },
3246 { "\xda" "Non-FS data" },
3247 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003248 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003249 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3250 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3251 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003252 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003253 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3254 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003255 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003256 { "\xf1" "SpeedStor" },
3257 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3258 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3259 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003260#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003261 { 0 }
3262};
3263
3264
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003265
3266/* A valid partition table sector ends in 0x55 0xaa */
3267static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003268part_table_flag(const char *b)
3269{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003270 return ((uint) b[510]) + (((uint) b[511]) << 8);
3271}
3272
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003273
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003274#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003275static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003276write_part_table_flag(char *b)
3277{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003278 b[510] = 0x55;
3279 b[511] = 0xaa;
3280}
3281
3282/* start_sect and nr_sects are stored little endian on all machines */
3283/* moreover, they are not aligned correctly */
3284static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003285store4_little_endian(unsigned char *cp, unsigned int val)
3286{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003287 cp[0] = (val & 0xff);
3288 cp[1] = ((val >> 8) & 0xff);
3289 cp[2] = ((val >> 16) & 0xff);
3290 cp[3] = ((val >> 24) & 0xff);
3291}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003292#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003293
3294static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003295read4_little_endian(const unsigned char *cp)
3296{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003297 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3298 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3299}
3300
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003301#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003302static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003303set_start_sect(struct partition *p, unsigned int start_sect)
3304{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003305 store4_little_endian(p->start4, start_sect);
3306}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003307#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003308
Eric Andersend9261492004-06-28 23:50:31 +00003309static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003310get_start_sect(const struct partition *p)
3311{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003312 return read4_little_endian(p->start4);
3313}
3314
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003315#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003316static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003317set_nr_sects(struct partition *p, int32_t nr_sects)
3318{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003319 store4_little_endian(p->size4, nr_sects);
3320}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003321#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003322
Eric Andersend9261492004-06-28 23:50:31 +00003323static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003324get_nr_sects(const struct partition *p)
3325{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003326 return read4_little_endian(p->size4);
3327}
3328
3329/* normally O_RDWR, -l option gives O_RDONLY */
3330static int type_open = O_RDWR;
3331
3332
Rob Landleyb73451d2006-02-24 16:29:00 +00003333static int ext_index; /* the prime extended partition */
3334static int listing; /* no aborts for fdisk -l */
3335static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003336#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3337static int dos_changed;
3338static int nowarn; /* no warnings for fdisk -l/-s */
3339#endif
3340
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003341
3342
Rob Landleyb73451d2006-02-24 16:29:00 +00003343static uint user_cylinders, user_heads, user_sectors;
3344static uint pt_heads, pt_sectors;
3345static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003346
Eric Andersend9261492004-06-28 23:50:31 +00003347static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003348
Eric Andersen040f4402003-07-30 08:40:37 +00003349static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003350
3351
3352static jmp_buf listingbuf;
3353
Rob Landleyb73451d2006-02-24 16:29:00 +00003354static void fdisk_fatal(enum failure why)
3355{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003356 const char *message;
3357
3358 if (listing) {
3359 close(fd);
3360 longjmp(listingbuf, 1);
3361 }
3362
3363 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003364 case unable_to_open:
3365 message = "Unable to open %s\n";
3366 break;
3367 case unable_to_read:
3368 message = "Unable to read %s\n";
3369 break;
3370 case unable_to_seek:
3371 message = "Unable to seek on %s\n";
3372 break;
3373 case unable_to_write:
3374 message = "Unable to write %s\n";
3375 break;
3376 case ioctl_error:
3377 message = "BLKGETSIZE ioctl failed on %s\n";
3378 break;
3379 default:
3380 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003381 }
3382
3383 fputc('\n', stderr);
3384 fprintf(stderr, message, disk_device);
3385 exit(1);
3386}
3387
3388static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003389seek_sector(off_t secno)
3390{
Eric Andersen0a92f352004-03-30 09:21:54 +00003391 off_t offset = secno * sector_size;
3392 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003393 fdisk_fatal(unable_to_seek);
3394}
3395
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003396#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003397static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003398write_sector(off_t secno, char *buf)
3399{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003400 seek_sector(secno);
3401 if (write(fd, buf, sector_size) != sector_size)
3402 fdisk_fatal(unable_to_write);
3403}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003404#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003405
3406/* Allocate a buffer and read a partition table sector */
3407static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003408read_pte(struct pte *pe, off_t offset)
3409{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003410 pe->offset = offset;
3411 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003412 seek_sector(offset);
3413 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3414 fdisk_fatal(unable_to_read);
3415#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003416 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003417#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003418 pe->part_table = pe->ext_pointer = NULL;
3419}
3420
3421static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003422get_partition_start(const struct pte *pe)
3423{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003424 return pe->offset + get_start_sect(pe->part_table);
3425}
3426
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003427#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003428/*
3429 * Avoid warning about DOS partitions when no DOS partition was changed.
3430 * Here a heuristic "is probably dos partition".
3431 * We might also do the opposite and warn in all cases except
3432 * for "is probably nondos partition".
3433 */
3434static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003435is_dos_partition(int t)
3436{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003437 return (t == 1 || t == 4 || t == 6 ||
3438 t == 0x0b || t == 0x0c || t == 0x0e ||
3439 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3440 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3441 t == 0xc1 || t == 0xc4 || t == 0xc6);
3442}
3443
3444static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003445menu(void)
3446{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003447#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003448 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003449 puts(_("Command action"));
3450 puts(_("\ta\ttoggle a read only flag")); /* sun */
3451 puts(_("\tb\tedit bsd disklabel"));
3452 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3453 puts(_("\td\tdelete a partition"));
3454 puts(_("\tl\tlist known partition types"));
3455 puts(_("\tm\tprint this menu"));
3456 puts(_("\tn\tadd a new partition"));
3457 puts(_("\to\tcreate a new empty DOS partition table"));
3458 puts(_("\tp\tprint the partition table"));
3459 puts(_("\tq\tquit without saving changes"));
3460 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3461 puts(_("\tt\tchange a partition's system id"));
3462 puts(_("\tu\tchange display/entry units"));
3463 puts(_("\tv\tverify the partition table"));
3464 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003465#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003466 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003467#endif
3468 } else
3469#endif
3470#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003471 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003472 puts(_("Command action"));
3473 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3474 puts(_("\tb\tedit bootfile entry")); /* sgi */
3475 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3476 puts(_("\td\tdelete a partition"));
3477 puts(_("\tl\tlist known partition types"));
3478 puts(_("\tm\tprint this menu"));
3479 puts(_("\tn\tadd a new partition"));
3480 puts(_("\to\tcreate a new empty DOS partition table"));
3481 puts(_("\tp\tprint the partition table"));
3482 puts(_("\tq\tquit without saving changes"));
3483 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3484 puts(_("\tt\tchange a partition's system id"));
3485 puts(_("\tu\tchange display/entry units"));
3486 puts(_("\tv\tverify the partition table"));
3487 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003488 } else
3489#endif
3490#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003491 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003492 puts(_("Command action"));
3493 puts(_("\tm\tprint this menu"));
3494 puts(_("\to\tcreate a new empty DOS partition table"));
3495 puts(_("\tq\tquit without saving changes"));
3496 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003497 } else
3498#endif
3499 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003500 puts(_("Command action"));
3501 puts(_("\ta\ttoggle a bootable flag"));
3502 puts(_("\tb\tedit bsd disklabel"));
3503 puts(_("\tc\ttoggle the dos compatibility flag"));
3504 puts(_("\td\tdelete a partition"));
3505 puts(_("\tl\tlist known partition types"));
3506 puts(_("\tm\tprint this menu"));
3507 puts(_("\tn\tadd a new partition"));
3508 puts(_("\to\tcreate a new empty DOS partition table"));
3509 puts(_("\tp\tprint the partition table"));
3510 puts(_("\tq\tquit without saving changes"));
3511 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3512 puts(_("\tt\tchange a partition's system id"));
3513 puts(_("\tu\tchange display/entry units"));
3514 puts(_("\tv\tverify the partition table"));
3515 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003516#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003517 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003518#endif
3519 }
3520}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003521#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3522
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003523
3524#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3525static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003526xmenu(void)
3527{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003528#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003529 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003530 puts(_("Command action"));
3531 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3532 puts(_("\tc\tchange number of cylinders"));
3533 puts(_("\td\tprint the raw data in the partition table"));
3534 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3535 puts(_("\th\tchange number of heads"));
3536 puts(_("\ti\tchange interleave factor")); /*sun*/
3537 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3538 puts(_("\tm\tprint this menu"));
3539 puts(_("\tp\tprint the partition table"));
3540 puts(_("\tq\tquit without saving changes"));
3541 puts(_("\tr\treturn to main menu"));
3542 puts(_("\ts\tchange number of sectors/track"));
3543 puts(_("\tv\tverify the partition table"));
3544 puts(_("\tw\twrite table to disk and exit"));
3545 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003546 } else
3547#endif
3548#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003549 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003550 puts(_("Command action"));
3551 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3552 puts(_("\tc\tchange number of cylinders"));
3553 puts(_("\td\tprint the raw data in the partition table"));
3554 puts(_("\te\tlist extended partitions")); /* !sun */
3555 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3556 puts(_("\th\tchange number of heads"));
3557 puts(_("\tm\tprint this menu"));
3558 puts(_("\tp\tprint the partition table"));
3559 puts(_("\tq\tquit without saving changes"));
3560 puts(_("\tr\treturn to main menu"));
3561 puts(_("\ts\tchange number of sectors/track"));
3562 puts(_("\tv\tverify the partition table"));
3563 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003564 } else
3565#endif
3566#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003567 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003568 puts(_("Command action"));
3569 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3570 puts(_("\tc\tchange number of cylinders"));
3571 puts(_("\td\tprint the raw data in the partition table"));
3572 puts(_("\te\tlist extended partitions")); /* !sun */
3573 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3574 puts(_("\th\tchange number of heads"));
3575 puts(_("\tm\tprint this menu"));
3576 puts(_("\tp\tprint the partition table"));
3577 puts(_("\tq\tquit without saving changes"));
3578 puts(_("\tr\treturn to main menu"));
3579 puts(_("\ts\tchange number of sectors/track"));
3580 puts(_("\tv\tverify the partition table"));
3581 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003582 } else
3583#endif
3584 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003585 puts(_("Command action"));
3586 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3587 puts(_("\tc\tchange number of cylinders"));
3588 puts(_("\td\tprint the raw data in the partition table"));
3589 puts(_("\te\tlist extended partitions")); /* !sun */
3590 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003591#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003592 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003593#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003594 puts(_("\th\tchange number of heads"));
3595 puts(_("\tm\tprint this menu"));
3596 puts(_("\tp\tprint the partition table"));
3597 puts(_("\tq\tquit without saving changes"));
3598 puts(_("\tr\treturn to main menu"));
3599 puts(_("\ts\tchange number of sectors/track"));
3600 puts(_("\tv\tverify the partition table"));
3601 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003602 }
3603}
3604#endif /* ADVANCED mode */
3605
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003606#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003607static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003608get_sys_types(void)
3609{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003610 return (
3611#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003612 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003613#endif
3614#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003615 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003616#endif
3617 i386_sys_types);
3618}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003619#else
3620#define get_sys_types() i386_sys_types
3621#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003622
3623static const char *partition_type(unsigned char type)
3624{
3625 int i;
3626 const struct systypes *types = get_sys_types();
3627
Rob Landleyb73451d2006-02-24 16:29:00 +00003628 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003629 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003630 return types[i].name + 1;
3631
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003632 return _("Unknown");
3633}
3634
3635
3636#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3637static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003638get_sysid(int i)
3639{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003640 return (
3641#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003642 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003643#endif
3644#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003645 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003646#endif
3647 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003648}
3649
3650void list_types(const struct systypes *sys)
3651{
3652 uint last[4], done = 0, next = 0, size;
3653 int i;
3654
3655 for (i = 0; sys[i].name; i++);
3656 size = i;
3657
3658 for (i = 3; i >= 0; i--)
3659 last[3 - i] = done += (size + i - done) / (i + 1);
3660 i = done = 0;
3661
3662 do {
3663 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003664 (unsigned char)sys[next].name[0],
3665 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003666 next = last[i++] + done;
3667 if (i > 3 || next >= last[i]) {
3668 i = 0;
3669 next = ++done;
3670 }
3671 } while (done < last[0]);
3672 putchar('\n');
3673}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003674#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003675
3676static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003677is_cleared_partition(const struct partition *p)
3678{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003679 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3680 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3681 get_start_sect(p) || get_nr_sects(p));
3682}
3683
3684static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003685clear_partition(struct partition *p)
3686{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003687 if (!p)
3688 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003689 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003690}
3691
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003692#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003693static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003694set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3695{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003696 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003697 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003698
3699 if (doext) {
3700 p = ptes[i].ext_pointer;
3701 offset = extended_offset;
3702 } else {
3703 p = ptes[i].part_table;
3704 offset = ptes[i].offset;
3705 }
3706 p->boot_ind = 0;
3707 p->sys_ind = sysid;
3708 set_start_sect(p, start - offset);
3709 set_nr_sects(p, stop - start + 1);
3710 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3711 start = heads*sectors*1024 - 1;
3712 set_hsc(p->head, p->sector, p->cyl, start);
3713 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3714 stop = heads*sectors*1024 - 1;
3715 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3716 ptes[i].changed = 1;
3717}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003718#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003719
3720static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003721test_c(const char **m, const char *mesg)
3722{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003723 int val = 0;
3724 if (!*m)
3725 fprintf(stderr, _("You must set"));
3726 else {
3727 fprintf(stderr, " %s", *m);
3728 val = 1;
3729 }
3730 *m = mesg;
3731 return val;
3732}
3733
3734static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003735warn_geometry(void)
3736{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003737 const char *m = NULL;
3738 int prev = 0;
3739
3740 if (!heads)
3741 prev = test_c(&m, _("heads"));
3742 if (!sectors)
3743 prev = test_c(&m, _("sectors"));
3744 if (!cylinders)
3745 prev = test_c(&m, _("cylinders"));
3746 if (!m)
3747 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003748
3749 fprintf(stderr, "%s%s.\n"
3750#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3751 "You can do this from the extra functions menu.\n"
3752#endif
3753 , prev ? _(" and ") : " ", m);
3754
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003755 return 1;
3756}
3757
3758static void update_units(void)
3759{
3760 int cyl_units = heads * sectors;
3761
3762 if (display_in_cyl_units && cyl_units)
3763 units_per_sector = cyl_units;
3764 else
3765 units_per_sector = 1; /* in sectors */
3766}
3767
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003768#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003769static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003770warn_cylinders(void)
3771{
Rob Landley5527b912006-02-25 03:46:10 +00003772 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003773 fprintf(stderr, _("\n"
3774"The number of cylinders for this disk is set to %d.\n"
3775"There is nothing wrong with that, but this is larger than 1024,\n"
3776"and could in certain setups cause problems with:\n"
3777"1) software that runs at boot time (e.g., old versions of LILO)\n"
3778"2) booting and partitioning software from other OSs\n"
3779" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3780 cylinders);
3781}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003782#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003783
3784static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003785read_extended(int ext)
3786{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003787 int i;
3788 struct pte *pex;
3789 struct partition *p, *q;
3790
3791 ext_index = ext;
3792 pex = &ptes[ext];
3793 pex->ext_pointer = pex->part_table;
3794
3795 p = pex->part_table;
3796 if (!get_start_sect(p)) {
3797 fprintf(stderr,
3798 _("Bad offset in primary extended partition\n"));
3799 return;
3800 }
3801
Rob Landleyb73451d2006-02-24 16:29:00 +00003802 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003803 struct pte *pe = &ptes[partitions];
3804
3805 if (partitions >= MAXIMUM_PARTS) {
3806 /* This is not a Linux restriction, but
3807 this program uses arrays of size MAXIMUM_PARTS.
3808 Do not try to `improve' this test. */
3809 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003810#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003811 fprintf(stderr,
3812 _("Warning: deleting partitions after %d\n"),
3813 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003814 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003815#endif
3816 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003817 return;
3818 }
3819
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003820 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003821
3822 if (!extended_offset)
3823 extended_offset = get_start_sect(p);
3824
3825 q = p = pt_offset(pe->sectorbuffer, 0);
3826 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003827 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003828 if (pe->ext_pointer)
3829 fprintf(stderr,
3830 _("Warning: extra link "
3831 "pointer in partition table"
3832 " %d\n"), partitions + 1);
3833 else
3834 pe->ext_pointer = p;
3835 } else if (p->sys_ind) {
3836 if (pe->part_table)
3837 fprintf(stderr,
3838 _("Warning: ignoring extra "
3839 "data in partition table"
3840 " %d\n"), partitions + 1);
3841 else
3842 pe->part_table = p;
3843 }
3844 }
3845
3846 /* very strange code here... */
3847 if (!pe->part_table) {
3848 if (q != pe->ext_pointer)
3849 pe->part_table = q;
3850 else
3851 pe->part_table = q + 1;
3852 }
3853 if (!pe->ext_pointer) {
3854 if (q != pe->part_table)
3855 pe->ext_pointer = q;
3856 else
3857 pe->ext_pointer = q + 1;
3858 }
3859
3860 p = pe->ext_pointer;
3861 partitions++;
3862 }
3863
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003864#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003865 /* remove empty links */
3866 remove:
3867 for (i = 4; i < partitions; i++) {
3868 struct pte *pe = &ptes[i];
3869
3870 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003871 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003872 printf("omitting empty partition (%d)\n", i+1);
3873 delete_partition(i);
3874 goto remove; /* numbering changed */
3875 }
3876 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003877#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003878}
3879
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003880#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003881static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003882create_doslabel(void)
3883{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003884 int i;
3885
3886 fprintf(stderr,
3887 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3888 "until you decide to write them. After that, of course, the previous\n"
3889 "content won't be recoverable.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00003890
3891 current_label_type = label_dos;
3892
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003893#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003894 possibly_osf_label = 0;
3895#endif
3896 partitions = 4;
3897
3898 for (i = 510-64; i < 510; i++)
3899 MBRbuffer[i] = 0;
3900 write_part_table_flag(MBRbuffer);
3901 extended_offset = 0;
3902 set_all_unchanged();
3903 set_changed(0);
3904 get_boot(create_empty_dos);
3905}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003906#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003907
3908static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003909get_sectorsize(void)
3910{
Rob Landley736e5252006-02-25 03:36:00 +00003911 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003912 int arg;
3913 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3914 sector_size = arg;
3915 if (sector_size != DEFAULT_SECTOR_SIZE)
3916 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003917 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003918 }
3919}
3920
Rob Landley88621d72006-08-29 19:41:06 +00003921static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003922get_kernel_geometry(void)
3923{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003924 struct hd_geometry geometry;
3925
3926 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3927 kern_heads = geometry.heads;
3928 kern_sectors = geometry.sectors;
3929 /* never use geometry.cylinders - it is truncated */
3930 }
3931}
3932
3933static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003934get_partition_table_geometry(void)
3935{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003936 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003937 struct partition *p;
3938 int i, h, s, hh, ss;
3939 int first = 1;
3940 int bad = 0;
3941
Eric Andersen3496fdc2006-01-30 23:09:20 +00003942 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003943 return;
3944
3945 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003946 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003947 p = pt_offset(bufp, i);
3948 if (p->sys_ind != 0) {
3949 h = p->end_head + 1;
3950 s = (p->end_sector & 077);
3951 if (first) {
3952 hh = h;
3953 ss = s;
3954 first = 0;
3955 } else if (hh != h || ss != s)
3956 bad = 1;
3957 }
3958 }
3959
3960 if (!first && !bad) {
3961 pt_heads = hh;
3962 pt_sectors = ss;
3963 }
3964}
3965
Rob Landleyb73451d2006-02-24 16:29:00 +00003966static void
3967get_geometry(void)
3968{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003969 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003970 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003971
3972 get_sectorsize();
3973 sec_fac = sector_size / 512;
3974#ifdef CONFIG_FEATURE_SUN_LABEL
3975 guess_device_type();
3976#endif
3977 heads = cylinders = sectors = 0;
3978 kern_heads = kern_sectors = 0;
3979 pt_heads = pt_sectors = 0;
3980
3981 get_kernel_geometry();
3982 get_partition_table_geometry();
3983
3984 heads = user_heads ? user_heads :
3985 pt_heads ? pt_heads :
3986 kern_heads ? kern_heads : 255;
3987 sectors = user_sectors ? user_sectors :
3988 pt_sectors ? pt_sectors :
3989 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003990 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3991 /* got bytes */
3992 } else {
3993 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003994
3995 if (ioctl(fd, BLKGETSIZE, &longsectors))
3996 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00003997 bytes = ((unsigned long long) longsectors) << 9;
3998 }
3999
4000 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004001
4002 sector_offset = 1;
4003 if (dos_compatible_flag)
4004 sector_offset = sectors;
4005
Eric Andersen040f4402003-07-30 08:40:37 +00004006 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004007 if (!cylinders)
4008 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004009}
4010
4011/*
4012 * Read MBR. Returns:
4013 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4014 * 0: found or created label
4015 * 1: I/O error
4016 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004017static int
4018get_boot(enum action what)
4019{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004020 int i;
4021
4022 partitions = 4;
4023
4024 for (i = 0; i < 4; i++) {
4025 struct pte *pe = &ptes[i];
4026
4027 pe->part_table = pt_offset(MBRbuffer, i);
4028 pe->ext_pointer = NULL;
4029 pe->offset = 0;
4030 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004031#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004032 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004033#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004034 }
4035
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004036#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004037 if (what == create_empty_sun && check_sun_label())
4038 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004039#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004040
4041 memset(MBRbuffer, 0, 512);
4042
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004043#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004044 if (what == create_empty_dos)
4045 goto got_dos_table; /* skip reading disk */
4046
4047 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004048 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4049 if (what == try_only)
4050 return 1;
4051 fdisk_fatal(unable_to_open);
4052 } else
4053 printf(_("You will not be able to write "
4054 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004055 }
4056
4057 if (512 != read(fd, MBRbuffer, 512)) {
4058 if (what == try_only)
4059 return 1;
4060 fdisk_fatal(unable_to_read);
4061 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004062#else
4063 if ((fd = open(disk_device, O_RDONLY)) < 0)
4064 return 1;
4065 if (512 != read(fd, MBRbuffer, 512))
4066 return 1;
4067#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004068
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004069 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004070
4071 update_units();
4072
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004073#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004074 if (check_sun_label())
4075 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004076#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004077
4078#ifdef CONFIG_FEATURE_SGI_LABEL
4079 if (check_sgi_label())
4080 return 0;
4081#endif
4082
4083#ifdef CONFIG_FEATURE_AIX_LABEL
4084 if (check_aix_label())
4085 return 0;
4086#endif
4087
4088#ifdef CONFIG_FEATURE_OSF_LABEL
4089 if (check_osf_label()) {
4090 possibly_osf_label = 1;
4091 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004092 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004093 return 0;
4094 }
4095 printf(_("This disk has both DOS and BSD magic.\n"
4096 "Give the 'b' command to go to BSD mode.\n"));
4097 }
4098#endif
4099
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004100#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004101 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004102#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004103
4104 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004105#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4106 return -1;
4107#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004108 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004109 case fdisk:
4110 fprintf(stderr,
4111 _("Device contains neither a valid DOS "
4112 "partition table, nor Sun, SGI or OSF "
4113 "disklabel\n"));
4114#ifdef __sparc__
4115#ifdef CONFIG_FEATURE_SUN_LABEL
4116 create_sunlabel();
4117#endif
4118#else
4119 create_doslabel();
4120#endif
4121 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004122 case try_only:
4123 return -1;
4124 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004125#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004126 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004127#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004128 break;
4129 default:
4130 fprintf(stderr, _("Internal error\n"));
4131 exit(1);
4132 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004133#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004134 }
4135
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004136#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004137 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004138#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004139 warn_geometry();
4140
4141 for (i = 0; i < 4; i++) {
4142 struct pte *pe = &ptes[i];
4143
Rob Landleyb73451d2006-02-24 16:29:00 +00004144 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004145 if (partitions != 4)
4146 fprintf(stderr, _("Ignoring extra extended "
4147 "partition %d\n"), i + 1);
4148 else
4149 read_extended(i);
4150 }
4151 }
4152
4153 for (i = 3; i < partitions; i++) {
4154 struct pte *pe = &ptes[i];
4155
4156 if (!valid_part_table_flag(pe->sectorbuffer)) {
4157 fprintf(stderr,
4158 _("Warning: invalid flag 0x%04x of partition "
4159 "table %d will be corrected by w(rite)\n"),
4160 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004161#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004162 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004163#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004164 }
4165 }
4166
4167 return 0;
4168}
4169
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004170#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004171/*
4172 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4173 * If the user hits Enter, DFLT is returned.
4174 * Answers like +10 are interpreted as offsets from BASE.
4175 *
4176 * There is no default if DFLT is not between LOW and HIGH.
4177 */
4178static uint
4179read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4180{
4181 uint i;
4182 int default_ok = 1;
4183 static char *ms = NULL;
4184 static int mslen = 0;
4185
4186 if (!ms || strlen(mesg)+100 > mslen) {
4187 mslen = strlen(mesg)+200;
4188 ms = xrealloc(ms,mslen);
4189 }
4190
4191 if (dflt < low || dflt > high)
4192 default_ok = 0;
4193
4194 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004195 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004196 mesg, low, high, dflt);
4197 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004198 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004199
4200 while (1) {
4201 int use_default = default_ok;
4202
4203 /* ask question and read answer */
4204 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004205 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004206 continue;
4207
Eric Andersen84bdea82004-05-19 10:49:17 +00004208 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004209 int minus = (*line_ptr == '-');
4210 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004211
Rob Landleyb73451d2006-02-24 16:29:00 +00004212 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004213
Rob Landleyb73451d2006-02-24 16:29:00 +00004214 while (isdigit(*++line_ptr))
4215 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004216
Rob Landleyb73451d2006-02-24 16:29:00 +00004217 switch (*line_ptr) {
4218 case 'c':
4219 case 'C':
4220 if (!display_in_cyl_units)
4221 i *= heads * sectors;
4222 break;
4223 case 'K':
4224 absolute = 1024;
4225 break;
4226 case 'k':
4227 absolute = 1000;
4228 break;
4229 case 'm':
4230 case 'M':
4231 absolute = 1000000;
4232 break;
4233 case 'g':
4234 case 'G':
4235 absolute = 1000000000;
4236 break;
4237 default:
4238 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004239 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004240 if (absolute) {
4241 unsigned long long bytes;
4242 unsigned long unit;
4243
4244 bytes = (unsigned long long) i * absolute;
4245 unit = sector_size * units_per_sector;
4246 bytes += unit/2; /* round */
4247 bytes /= unit;
4248 i = bytes;
4249 }
4250 if (minus)
4251 i = -i;
4252 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004253 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004254 i = atoi(line_ptr);
4255 while (isdigit(*line_ptr)) {
4256 line_ptr++;
4257 use_default = 0;
4258 }
4259 }
4260 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004261 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004262 if (i >= low && i <= high)
4263 break;
4264 else
4265 printf(_("Value out of range.\n"));
4266 }
4267 return i;
4268}
4269
Rob Landleyb73451d2006-02-24 16:29:00 +00004270static int
4271get_partition(int warn, int max)
4272{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004273 struct pte *pe;
4274 int i;
4275
4276 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4277 pe = &ptes[i];
4278
4279 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004280 if (
4281 (
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00004282 label_sun != current_label_type &&
4283 label_sgi != current_label_type &&
Rob Landley5527b912006-02-25 03:46:10 +00004284 !pe->part_table->sys_ind
4285 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004286#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004287 || (
4288 label_sun == current_label_type &&
4289 (
4290 !sunlabel->partitions[i].num_sectors
4291 || !sunlabel->infos[i].id
4292 )
4293 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004294#endif
4295#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004296 || (
4297 label_sgi == current_label_type &&
4298 !sgi_get_num_sectors(i)
4299 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004300#endif
Rob Landley5527b912006-02-25 03:46:10 +00004301 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004302 fprintf(stderr,
4303 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004304 i+1
4305 );
4306 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004307 }
4308 return i;
4309}
4310
4311static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004312get_existing_partition(int warn, int max)
4313{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004314 int pno = -1;
4315 int i;
4316
4317 for (i = 0; i < max; i++) {
4318 struct pte *pe = &ptes[i];
4319 struct partition *p = pe->part_table;
4320
4321 if (p && !is_cleared_partition(p)) {
4322 if (pno >= 0)
4323 goto not_unique;
4324 pno = i;
4325 }
4326 }
4327 if (pno >= 0) {
4328 printf(_("Selected partition %d\n"), pno+1);
4329 return pno;
4330 }
4331 printf(_("No partition is defined yet!\n"));
4332 return -1;
4333
4334 not_unique:
4335 return get_partition(warn, max);
4336}
4337
4338static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004339get_nonexisting_partition(int warn, int max)
4340{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004341 int pno = -1;
4342 int i;
4343
4344 for (i = 0; i < max; i++) {
4345 struct pte *pe = &ptes[i];
4346 struct partition *p = pe->part_table;
4347
4348 if (p && is_cleared_partition(p)) {
4349 if (pno >= 0)
4350 goto not_unique;
4351 pno = i;
4352 }
4353 }
4354 if (pno >= 0) {
4355 printf(_("Selected partition %d\n"), pno+1);
4356 return pno;
4357 }
4358 printf(_("All primary partitions have been defined already!\n"));
4359 return -1;
4360
4361 not_unique:
4362 return get_partition(warn, max);
4363}
4364
4365
4366void change_units(void)
4367{
4368 display_in_cyl_units = !display_in_cyl_units;
4369 update_units();
4370 printf(_("Changing display/entry units to %s\n"),
4371 str_units(PLURAL));
4372}
4373
4374static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004375toggle_active(int i)
4376{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004377 struct pte *pe = &ptes[i];
4378 struct partition *p = pe->part_table;
4379
Rob Landleyb73451d2006-02-24 16:29:00 +00004380 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004381 fprintf(stderr,
4382 _("WARNING: Partition %d is an extended partition\n"),
4383 i + 1);
4384 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4385 pe->changed = 1;
4386}
4387
4388static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004389toggle_dos_compatibility_flag(void)
4390{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004391 dos_compatible_flag = ~dos_compatible_flag;
4392 if (dos_compatible_flag) {
4393 sector_offset = sectors;
4394 printf(_("DOS Compatibility flag is set\n"));
4395 }
4396 else {
4397 sector_offset = 1;
4398 printf(_("DOS Compatibility flag is not set\n"));
4399 }
4400}
4401
4402static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004403delete_partition(int i)
4404{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004405 struct pte *pe = &ptes[i];
4406 struct partition *p = pe->part_table;
4407 struct partition *q = pe->ext_pointer;
4408
4409/* Note that for the fifth partition (i == 4) we don't actually
4410 * decrement partitions.
4411 */
4412
4413 if (warn_geometry())
4414 return; /* C/H/S not set */
4415 pe->changed = 1;
4416
4417#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004418 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004419 sun_delete_partition(i);
4420 return;
4421 }
4422#endif
4423#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004424 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004425 sgi_delete_partition(i);
4426 return;
4427 }
4428#endif
4429
4430 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004431 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004432 partitions = 4;
4433 ptes[ext_index].ext_pointer = NULL;
4434 extended_offset = 0;
4435 }
4436 clear_partition(p);
4437 return;
4438 }
4439
4440 if (!q->sys_ind && i > 4) {
4441 /* the last one in the chain - just delete */
4442 --partitions;
4443 --i;
4444 clear_partition(ptes[i].ext_pointer);
4445 ptes[i].changed = 1;
4446 } else {
4447 /* not the last one - further ones will be moved down */
4448 if (i > 4) {
4449 /* delete this link in the chain */
4450 p = ptes[i-1].ext_pointer;
4451 *p = *q;
4452 set_start_sect(p, get_start_sect(q));
4453 set_nr_sects(p, get_nr_sects(q));
4454 ptes[i-1].changed = 1;
4455 } else if (partitions > 5) { /* 5 will be moved to 4 */
4456 /* the first logical in a longer chain */
4457 pe = &ptes[5];
4458
4459 if (pe->part_table) /* prevent SEGFAULT */
4460 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004461 get_partition_start(pe) -
4462 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004463 pe->offset = extended_offset;
4464 pe->changed = 1;
4465 }
4466
4467 if (partitions > 5) {
4468 partitions--;
4469 while (i < partitions) {
4470 ptes[i] = ptes[i+1];
4471 i++;
4472 }
4473 } else
4474 /* the only logical: clear only */
4475 clear_partition(ptes[i].part_table);
4476 }
4477}
4478
4479static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004480change_sysid(void)
4481{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004482 int i, sys, origsys;
4483 struct partition *p;
4484
Eric Andersen040f4402003-07-30 08:40:37 +00004485#ifdef CONFIG_FEATURE_SGI_LABEL
4486 /* If sgi_label then don't use get_existing_partition,
4487 let the user select a partition, since get_existing_partition()
4488 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004489 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004490 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004491 } else {
4492 i = get_partition(0, partitions);
4493 }
4494#else
4495 i = get_existing_partition(0, partitions);
4496#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004497 if (i == -1)
4498 return;
4499 p = ptes[i].part_table;
4500 origsys = sys = get_sysid(i);
4501
4502 /* if changing types T to 0 is allowed, then
4503 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004504 if (!sys && label_sgi != current_label_type &&
4505 label_sun != current_label_type && !get_nr_sects(p))
4506 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004507 printf(_("Partition %d does not exist yet!\n"), i + 1);
Denis Vlasenko92758142006-10-03 19:56:34 +00004508 } else while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004509 sys = read_hex (get_sys_types());
4510
Rob Landley5527b912006-02-25 03:46:10 +00004511 if (!sys && label_sgi != current_label_type &&
4512 label_sun != current_label_type)
4513 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004514 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004515 "(but not to Linux). Having partitions of\n"
4516 "type 0 is probably unwise. You can delete\n"
4517 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004518 /* break; */
4519 }
4520
Rob Landley5527b912006-02-25 03:46:10 +00004521 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004522 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004523 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004524 " an extended one or vice versa\n"
4525 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004526 break;
4527 }
4528 }
4529
4530 if (sys < 256) {
4531#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004532 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004533 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004534 "as Whole disk (5),\n"
4535 "as SunOS/Solaris expects it and "
4536 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004537#endif
4538#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004539 if (label_sgi == current_label_type &&
4540 (
4541 (i == 10 && sys != ENTIRE_DISK) ||
4542 (i == 8 && sys != 0)
4543 )
4544 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004545 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004546 "as volume header (0),\nand "
4547 "partition 11 as entire volume (6)"
4548 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004549 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004550#endif
4551 if (sys == origsys)
4552 break;
4553#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004554 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004555 sun_change_sysid(i, sys);
4556 } else
4557#endif
4558#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004559 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004560 sgi_change_sysid(i, sys);
4561 } else
4562#endif
4563 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004564
Rob Landleyb73451d2006-02-24 16:29:00 +00004565 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004566 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004567 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004568 ptes[i].changed = 1;
4569 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004570 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004571 dos_changed = 1;
4572 break;
4573 }
4574 }
4575}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004576#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4577
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004578
4579/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4580 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4581 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4582 * Lubkin Oct. 1991). */
4583
Rob Landleyb73451d2006-02-24 16:29:00 +00004584static void
4585long2chs(ulong ls, uint *c, uint *h, uint *s)
4586{
4587 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004588
4589 *c = ls / spc;
4590 ls = ls % spc;
4591 *h = ls / sectors;
4592 *s = ls % sectors + 1; /* sectors count from 1 */
4593}
4594
Rob Landleyb73451d2006-02-24 16:29:00 +00004595static void
4596check_consistency(const struct partition *p, int partition)
4597{
4598 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4599 uint pec, peh, pes; /* physical ending c, h, s */
4600 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4601 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004602
4603 if (!heads || !sectors || (partition >= 4))
4604 return; /* do not check extended partitions */
4605
4606/* physical beginning c, h, s */
4607 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4608 pbh = p->head;
4609 pbs = p->sector & 0x3f;
4610
4611/* physical ending c, h, s */
4612 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4613 peh = p->end_head;
4614 pes = p->end_sector & 0x3f;
4615
4616/* compute logical beginning (c, h, s) */
4617 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4618
4619/* compute logical ending (c, h, s) */
4620 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4621
4622/* Same physical / logical beginning? */
4623 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4624 printf(_("Partition %d has different physical/logical "
4625 "beginnings (non-Linux?):\n"), partition + 1);
4626 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4627 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4628 }
4629
4630/* Same physical / logical ending? */
4631 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4632 printf(_("Partition %d has different physical/logical "
4633 "endings:\n"), partition + 1);
4634 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4635 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4636 }
4637
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004638/* Ending on cylinder boundary? */
4639 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004640 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004641 partition + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004642 }
4643}
4644
4645static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004646list_disk_geometry(void)
4647{
Eric Andersen040f4402003-07-30 08:40:37 +00004648 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004649 long megabytes = bytes/1000000;
4650
4651 if (megabytes < 10000)
4652 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004653 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004654 else
4655 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004656 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004657 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004658 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004659 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004660 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004661 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004662 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004663 str_units(PLURAL),
4664 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004665}
4666
4667/*
4668 * Check whether partition entries are ordered by their starting positions.
4669 * Return 0 if OK. Return i if partition i should have been earlier.
4670 * Two separate checks: primary and logical partitions.
4671 */
4672static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004673wrong_p_order(int *prev)
4674{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004675 const struct pte *pe;
4676 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004677 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004678 int i, last_i = 0;
4679
4680 for (i = 0 ; i < partitions; i++) {
4681 if (i == 4) {
4682 last_i = 4;
4683 last_p_start_pos = 0;
4684 }
4685 pe = &ptes[i];
4686 if ((p = pe->part_table)->sys_ind) {
4687 p_start_pos = get_partition_start(pe);
4688
4689 if (last_p_start_pos > p_start_pos) {
4690 if (prev)
4691 *prev = last_i;
4692 return i;
4693 }
4694
4695 last_p_start_pos = p_start_pos;
4696 last_i = i;
4697 }
4698 }
4699 return 0;
4700}
4701
4702#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4703/*
4704 * Fix the chain of logicals.
4705 * extended_offset is unchanged, the set of sectors used is unchanged
4706 * The chain is sorted so that sectors increase, and so that
4707 * starting sectors increase.
4708 *
4709 * After this it may still be that cfdisk doesnt like the table.
4710 * (This is because cfdisk considers expanded parts, from link to
4711 * end of partition, and these may still overlap.)
4712 * Now
4713 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4714 * may help.
4715 */
4716static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004717fix_chain_of_logicals(void)
4718{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004719 int j, oj, ojj, sj, sjj;
4720 struct partition *pj,*pjj,tmp;
4721
4722 /* Stage 1: sort sectors but leave sector of part 4 */
4723 /* (Its sector is the global extended_offset.) */
4724 stage1:
4725 for (j = 5; j < partitions-1; j++) {
4726 oj = ptes[j].offset;
4727 ojj = ptes[j+1].offset;
4728 if (oj > ojj) {
4729 ptes[j].offset = ojj;
4730 ptes[j+1].offset = oj;
4731 pj = ptes[j].part_table;
4732 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4733 pjj = ptes[j+1].part_table;
4734 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4735 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004736 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004737 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004738 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004739 goto stage1;
4740 }
4741 }
4742
4743 /* Stage 2: sort starting sectors */
4744 stage2:
4745 for (j = 4; j < partitions-1; j++) {
4746 pj = ptes[j].part_table;
4747 pjj = ptes[j+1].part_table;
4748 sj = get_start_sect(pj);
4749 sjj = get_start_sect(pjj);
4750 oj = ptes[j].offset;
4751 ojj = ptes[j+1].offset;
4752 if (oj+sj > ojj+sjj) {
4753 tmp = *pj;
4754 *pj = *pjj;
4755 *pjj = tmp;
4756 set_start_sect(pj, ojj+sjj-oj);
4757 set_start_sect(pjj, oj+sj-ojj);
4758 goto stage2;
4759 }
4760 }
4761
4762 /* Probably something was changed */
4763 for (j = 4; j < partitions; j++)
4764 ptes[j].changed = 1;
4765}
4766
4767
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004768static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004769fix_partition_table_order(void)
4770{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004771 struct pte *pei, *pek;
4772 int i,k;
4773
4774 if (!wrong_p_order(NULL)) {
4775 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4776 return;
4777 }
4778
4779 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4780 /* partition i should have come earlier, move it */
4781 /* We have to move data in the MBR */
4782 struct partition *pi, *pk, *pe, pbuf;
4783 pei = &ptes[i];
4784 pek = &ptes[k];
4785
4786 pe = pei->ext_pointer;
4787 pei->ext_pointer = pek->ext_pointer;
4788 pek->ext_pointer = pe;
4789
4790 pi = pei->part_table;
4791 pk = pek->part_table;
4792
4793 memmove(&pbuf, pi, sizeof(struct partition));
4794 memmove(pi, pk, sizeof(struct partition));
4795 memmove(pk, &pbuf, sizeof(struct partition));
4796
4797 pei->changed = pek->changed = 1;
4798 }
4799
4800 if (i)
4801 fix_chain_of_logicals();
4802
4803 printf("Done.\n");
4804
4805}
4806#endif
4807
4808static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004809list_table(int xtra)
4810{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004811 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004812 int i, w;
4813
4814#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004815 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004816 sun_list_table(xtra);
4817 return;
4818 }
4819#endif
4820
4821#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004822 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004823 sgi_list_table(xtra);
4824 return;
4825 }
4826#endif
4827
4828 list_disk_geometry();
4829
4830#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004831 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004832 xbsd_print_disklabel(xtra);
4833 return;
4834 }
4835#endif
4836
4837 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4838 but if the device name ends in a digit, say /dev/foo1,
4839 then the partition is called /dev/foo1p3. */
4840 w = strlen(disk_device);
4841 if (w && isdigit(disk_device[w-1]))
4842 w++;
4843 if (w < 5)
4844 w = 5;
4845
4846 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004847 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004848
4849 for (i = 0; i < partitions; i++) {
4850 const struct pte *pe = &ptes[i];
4851
4852 p = pe->part_table;
4853 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004854 off_t psects = get_nr_sects(p);
4855 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004856 unsigned int podd = 0;
4857
4858 if (sector_size < 1024) {
4859 pblocks /= (1024 / sector_size);
4860 podd = psects % (1024 / sector_size);
4861 }
4862 if (sector_size > 1024)
4863 pblocks *= (sector_size / 1024);
4864 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004865 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004866 partname(disk_device, i+1, w+2),
4867/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4868 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004869/* start */ (unsigned long long) cround(get_partition_start(pe)),
4870/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004871 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004872/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004873/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004874/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004875 check_consistency(p, i);
4876 }
4877 }
4878
4879 /* Is partition table in disk order? It need not be, but... */
4880 /* partition table entries are not checked for correct order if this
4881 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004882 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4883 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004884 printf(_("\nPartition table entries are not in disk order\n"));
4885 }
4886}
4887
4888#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4889static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004890x_list_table(int extend)
4891{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004892 const struct pte *pe;
4893 const struct partition *p;
4894 int i;
4895
4896 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4897 disk_device, heads, sectors, cylinders);
4898 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4899 for (i = 0 ; i < partitions; i++) {
4900 pe = &ptes[i];
4901 p = (extend ? pe->ext_pointer : pe->part_table);
4902 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004903 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004904 i + 1, p->boot_ind, p->head,
4905 sector(p->sector),
4906 cylinder(p->sector, p->cyl), p->end_head,
4907 sector(p->end_sector),
4908 cylinder(p->end_sector, p->end_cyl),
4909 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4910 if (p->sys_ind)
4911 check_consistency(p, i);
4912 }
4913 }
4914}
4915#endif
4916
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004917#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004918static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004919fill_bounds(off_t *first, off_t *last)
4920{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004921 int i;
4922 const struct pte *pe = &ptes[0];
4923 const struct partition *p;
4924
4925 for (i = 0; i < partitions; pe++,i++) {
4926 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004927 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004928 first[i] = 0xffffffff;
4929 last[i] = 0;
4930 } else {
4931 first[i] = get_partition_start(pe);
4932 last[i] = first[i] + get_nr_sects(p) - 1;
4933 }
4934 }
4935}
4936
4937static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004938check(int n, uint h, uint s, uint c, off_t start)
4939{
Eric Andersend9261492004-06-28 23:50:31 +00004940 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004941
4942 real_s = sector(s) - 1;
4943 real_c = cylinder(s, c);
4944 total = (real_c * sectors + real_s) * heads + h;
4945 if (!total)
4946 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4947 if (h >= heads)
4948 fprintf(stderr,
4949 _("Partition %d: head %d greater than maximum %d\n"),
4950 n, h + 1, heads);
4951 if (real_s >= sectors)
4952 fprintf(stderr, _("Partition %d: sector %d greater than "
4953 "maximum %d\n"), n, s, sectors);
4954 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004955 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4956 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004957 if (cylinders <= 1024 && start != total)
4958 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004959 _("Partition %d: previous sectors %llu disagrees with "
4960 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004961}
4962
4963static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004964verify(void)
4965{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004966 int i, j;
4967 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00004968 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004969 struct partition *p;
4970
4971 if (warn_geometry())
4972 return;
4973
4974#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004975 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004976 verify_sun();
4977 return;
4978 }
4979#endif
4980#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004981 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004982 verify_sgi(1);
4983 return;
4984 }
4985#endif
4986
4987 fill_bounds(first, last);
4988 for (i = 0; i < partitions; i++) {
4989 struct pte *pe = &ptes[i];
4990
4991 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004992 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004993 check_consistency(p, i);
4994 if (get_partition_start(pe) < first[i])
4995 printf(_("Warning: bad start-of-data in "
4996 "partition %d\n"), i + 1);
4997 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4998 last[i]);
4999 total += last[i] + 1 - first[i];
5000 for (j = 0; j < i; j++)
5001 if ((first[i] >= first[j] && first[i] <= last[j])
5002 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5003 printf(_("Warning: partition %d overlaps "
5004 "partition %d.\n"), j + 1, i + 1);
5005 total += first[i] >= first[j] ?
5006 first[i] : first[j];
5007 total -= last[i] <= last[j] ?
5008 last[i] : last[j];
5009 }
5010 }
5011 }
5012
5013 if (extended_offset) {
5014 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005015 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005016 get_nr_sects(pex->part_table) - 1;
5017
5018 for (i = 4; i < partitions; i++) {
5019 total++;
5020 p = ptes[i].part_table;
5021 if (!p->sys_ind) {
5022 if (i != 4 || i + 1 < partitions)
5023 printf(_("Warning: partition %d "
5024 "is empty\n"), i + 1);
5025 }
5026 else if (first[i] < extended_offset ||
5027 last[i] > e_last)
5028 printf(_("Logical partition %d not entirely in "
5029 "partition %d\n"), i + 1, ext_index + 1);
5030 }
5031 }
5032
5033 if (total > heads * sectors * cylinders)
5034 printf(_("Total allocated sectors %d greater than the maximum "
5035 "%d\n"), total, heads * sectors * cylinders);
5036 else if ((total = heads * sectors * cylinders - total) != 0)
5037 printf(_("%d unallocated sectors\n"), total);
5038}
5039
5040static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005041add_partition(int n, int sys)
5042{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005043 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005044 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005045 struct partition *p = ptes[n].part_table;
5046 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005047 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005048 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005049 first[partitions], last[partitions];
5050
5051 if (p && p->sys_ind) {
5052 printf(_("Partition %d is already defined. Delete "
5053 "it before re-adding it.\n"), n + 1);
5054 return;
5055 }
5056 fill_bounds(first, last);
5057 if (n < 4) {
5058 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005059 if (display_in_cyl_units || !total_number_of_sectors)
5060 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005061 else
Eric Andersen040f4402003-07-30 08:40:37 +00005062 llimit = total_number_of_sectors - 1;
5063 limit = llimit;
5064 if (limit != llimit)
5065 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005066 if (extended_offset) {
5067 first[ext_index] = extended_offset;
5068 last[ext_index] = get_start_sect(q) +
5069 get_nr_sects(q) - 1;
5070 }
5071 } else {
5072 start = extended_offset + sector_offset;
5073 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5074 }
5075 if (display_in_cyl_units)
5076 for (i = 0; i < partitions; i++)
5077 first[i] = (cround(first[i]) - 1) * units_per_sector;
5078
5079 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5080 do {
5081 temp = start;
5082 for (i = 0; i < partitions; i++) {
5083 int lastplusoff;
5084
5085 if (start == ptes[i].offset)
5086 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005087 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005088 if (start >= first[i] && start <= lastplusoff)
5089 start = lastplusoff + 1;
5090 }
5091 if (start > limit)
5092 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005093 if (start >= temp+units_per_sector && num_read) {
Eric Andersend9261492004-06-28 23:50:31 +00005094 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005095 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005096 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005097 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005098 if (!num_read && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005099 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005100
5101 saved_start = start;
5102 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5103 0, mesg);
5104 if (display_in_cyl_units) {
5105 start = (start - 1) * units_per_sector;
5106 if (start < saved_start) start = saved_start;
5107 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005108 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005109 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005110 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005111 if (n > 4) { /* NOT for fifth partition */
5112 struct pte *pe = &ptes[n];
5113
5114 pe->offset = start - sector_offset;
5115 if (pe->offset == extended_offset) { /* must be corrected */
5116 pe->offset++;
5117 if (sector_offset == 1)
5118 start++;
5119 }
5120 }
5121
5122 for (i = 0; i < partitions; i++) {
5123 struct pte *pe = &ptes[i];
5124
5125 if (start < pe->offset && limit >= pe->offset)
5126 limit = pe->offset - 1;
5127 if (start < first[i] && limit >= first[i])
5128 limit = first[i] - 1;
5129 }
5130 if (start > limit) {
5131 printf(_("No free sectors available\n"));
5132 if (n > 4)
5133 partitions--;
5134 return;
5135 }
5136 if (cround(start) == cround(limit)) {
5137 stop = limit;
5138 } else {
5139 snprintf(mesg, sizeof(mesg),
5140 _("Last %s or +size or +sizeM or +sizeK"),
5141 str_units(SINGULAR));
5142 stop = read_int(cround(start), cround(limit), cround(limit),
5143 cround(start), mesg);
5144 if (display_in_cyl_units) {
5145 stop = stop * units_per_sector - 1;
5146 if (stop >limit)
5147 stop = limit;
5148 }
5149 }
5150
5151 set_partition(n, 0, start, stop, sys);
5152 if (n > 4)
5153 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5154
Rob Landleyb73451d2006-02-24 16:29:00 +00005155 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005156 struct pte *pe4 = &ptes[4];
5157 struct pte *pen = &ptes[n];
5158
5159 ext_index = n;
5160 pen->ext_pointer = p;
5161 pe4->offset = extended_offset = start;
Rob Landley081e3842006-08-03 20:07:35 +00005162 pe4->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005163 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5164 pe4->ext_pointer = pe4->part_table + 1;
5165 pe4->changed = 1;
5166 partitions = 5;
5167 }
5168}
5169
5170static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005171add_logical(void)
5172{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005173 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5174 struct pte *pe = &ptes[partitions];
5175
Rob Landley081e3842006-08-03 20:07:35 +00005176 pe->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005177 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5178 pe->ext_pointer = pe->part_table + 1;
5179 pe->offset = 0;
5180 pe->changed = 1;
5181 partitions++;
5182 }
5183 add_partition(partitions - 1, LINUX_NATIVE);
5184}
5185
5186static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005187new_partition(void)
5188{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005189 int i, free_primary = 0;
5190
5191 if (warn_geometry())
5192 return;
5193
5194#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005195 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005196 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5197 return;
5198 }
5199#endif
5200#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005201 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005202 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5203 return;
5204 }
5205#endif
5206#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005207 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005208 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5209 "\n\tIf you want to add DOS-type partitions, create"
5210 "\n\ta new empty DOS partition table first. (Use o.)"
5211 "\n\tWARNING: "
5212 "This will destroy the present disk contents.\n"));
5213 return;
5214 }
5215#endif
5216
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005217 for (i = 0; i < 4; i++)
5218 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005219
Rob Landleyb73451d2006-02-24 16:29:00 +00005220 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005221 printf(_("The maximum number of partitions has been created\n"));
5222 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005223 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005224
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005225 if (!free_primary) {
5226 if (extended_offset)
5227 add_logical();
5228 else
5229 printf(_("You must delete some partition and add "
5230 "an extended partition first\n"));
5231 } else {
5232 char c, line[LINE_LENGTH];
5233 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5234 "partition (1-4)\n",
5235 "Command action", (extended_offset ?
5236 "l logical (5 or over)" : "e extended"));
5237 while (1) {
5238 if ((c = read_char(line)) == 'p' || c == 'P') {
5239 i = get_nonexisting_partition(0, 4);
5240 if (i >= 0)
5241 add_partition(i, LINUX_NATIVE);
5242 return;
5243 }
5244 else if (c == 'l' && extended_offset) {
5245 add_logical();
5246 return;
5247 }
5248 else if (c == 'e' && !extended_offset) {
5249 i = get_nonexisting_partition(0, 4);
5250 if (i >= 0)
5251 add_partition(i, EXTENDED);
5252 return;
5253 }
5254 else
5255 printf(_("Invalid partition number "
5256 "for type `%c'\n"), c);
5257 }
5258 }
5259}
5260
5261static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005262write_table(void)
5263{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005264 int i;
5265
Rob Landley5527b912006-02-25 03:46:10 +00005266 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005267 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005268 if (ptes[i].changed)
5269 ptes[3].changed = 1;
5270 for (i = 3; i < partitions; i++) {
5271 struct pte *pe = &ptes[i];
5272
5273 if (pe->changed) {
5274 write_part_table_flag(pe->sectorbuffer);
5275 write_sector(pe->offset, pe->sectorbuffer);
5276 }
5277 }
5278 }
5279#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005280 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005281 /* no test on change? the printf below might be mistaken */
5282 sgi_write_table();
5283 }
5284#endif
5285#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005286 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005287 int needw = 0;
5288
Rob Landleyb73451d2006-02-24 16:29:00 +00005289 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005290 if (ptes[i].changed)
5291 needw = 1;
5292 if (needw)
5293 sun_write_table();
5294 }
5295#endif
5296
5297 printf(_("The partition table has been altered!\n\n"));
5298 reread_partition_table(1);
5299}
5300
Rob Landleyb73451d2006-02-24 16:29:00 +00005301static void
5302reread_partition_table(int leave)
5303{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005304 int error = 0;
5305 int i;
5306
5307 printf(_("Calling ioctl() to re-read partition table.\n"));
5308 sync();
5309 sleep(2);
5310 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5311 error = errno;
5312 } else {
5313 /* some kernel versions (1.2.x) seem to have trouble
5314 rereading the partition table, but if asked to do it
5315 twice, the second time works. - biro@yggdrasil.com */
5316 sync();
5317 sleep(2);
5318 if ((i = ioctl(fd, BLKRRPART)) != 0)
5319 error = errno;
5320 }
5321
5322 if (i) {
5323 printf(_("\nWARNING: Re-reading the partition table "
5324 "failed with error %d: %s.\n"
5325 "The kernel still uses the old table.\n"
5326 "The new table will be used "
5327 "at the next reboot.\n"),
5328 error, strerror(error));
5329 }
5330
5331 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005332 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005333 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5334 "partitions, please see the fdisk manual page for additional\n"
5335 "information.\n"));
5336
5337 if (leave) {
5338 close(fd);
5339
5340 printf(_("Syncing disks.\n"));
5341 sync();
5342 sleep(4); /* for sync() */
5343 exit(!!i);
5344 }
5345}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005346#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005347
5348#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5349#define MAX_PER_LINE 16
5350static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005351print_buffer(char *pbuffer)
5352{
5353 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005354
5355 for (i = 0, l = 0; i < sector_size; i++, l++) {
5356 if (l == 0)
5357 printf("0x%03X:", i);
5358 printf(" %02X", (unsigned char) pbuffer[i]);
5359 if (l == MAX_PER_LINE - 1) {
5360 printf("\n");
5361 l = -1;
5362 }
5363 }
5364 if (l > 0)
5365 printf("\n");
5366 printf("\n");
5367}
5368
5369
5370static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005371print_raw(void)
5372{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005373 int i;
5374
5375 printf(_("Device: %s\n"), disk_device);
5376#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005377 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005378 print_buffer(MBRbuffer);
5379 else
5380#endif
5381 for (i = 3; i < partitions; i++)
5382 print_buffer(ptes[i].sectorbuffer);
5383}
5384
5385static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005386move_begin(int i)
5387{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005388 struct pte *pe = &ptes[i];
5389 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005390 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005391
5392 if (warn_geometry())
5393 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005394 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005395 printf(_("Partition %d has no data area\n"), i + 1);
5396 return;
5397 }
5398 first = get_partition_start(pe);
5399 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005400 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005401
5402 if (new != get_nr_sects(p)) {
5403 first = get_nr_sects(p) + get_start_sect(p) - new;
5404 set_nr_sects(p, first);
5405 set_start_sect(p, new);
5406 pe->changed = 1;
5407 }
5408}
5409
5410static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005411xselect(void)
5412{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005413 char c;
5414
Rob Landleyb73451d2006-02-24 16:29:00 +00005415 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005416 putchar('\n');
5417 c = tolower(read_char(_("Expert command (m for help): ")));
5418 switch (c) {
5419 case 'a':
5420#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005421 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005422 sun_set_alt_cyl();
5423#endif
5424 break;
5425 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005426 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005427 move_begin(get_partition(0, partitions));
5428 break;
5429 case 'c':
5430 user_cylinders = cylinders =
5431 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005432 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005433#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005434 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005435 sun_set_ncyl(cylinders);
5436#endif
Rob Landley5527b912006-02-25 03:46:10 +00005437 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005438 warn_cylinders();
5439 break;
5440 case 'd':
5441 print_raw();
5442 break;
5443 case 'e':
5444#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005445 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005446 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005447 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005448#endif
5449#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005450 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005451 sun_set_xcyl();
5452 else
5453#endif
Rob Landley5527b912006-02-25 03:46:10 +00005454 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005455 x_list_table(1);
5456 break;
5457 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005458 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005459 fix_partition_table_order();
5460 break;
5461 case 'g':
5462#ifdef CONFIG_FEATURE_SGI_LABEL
5463 create_sgilabel();
5464#endif
5465 break;
5466 case 'h':
5467 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005468 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005469 update_units();
5470 break;
5471 case 'i':
5472#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005473 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005474 sun_set_ilfact();
5475#endif
5476 break;
5477 case 'o':
5478#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005479 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005480 sun_set_rspeed();
5481#endif
5482 break;
5483 case 'p':
5484#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005485 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005486 list_table(1);
5487 else
5488#endif
5489 x_list_table(0);
5490 break;
5491 case 'q':
5492 close(fd);
5493 printf("\n");
5494 exit(0);
5495 case 'r':
5496 return;
5497 case 's':
5498 user_sectors = sectors = read_int(1, sectors, 63, 0,
5499 _("Number of sectors"));
5500 if (dos_compatible_flag) {
5501 sector_offset = sectors;
5502 fprintf(stderr, _("Warning: setting "
5503 "sector offset for DOS "
5504 "compatiblity\n"));
5505 }
5506 update_units();
5507 break;
5508 case 'v':
5509 verify();
5510 break;
5511 case 'w':
5512 write_table(); /* does not return */
5513 break;
5514 case 'y':
5515#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005516 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005517 sun_set_pcylcount();
5518#endif
5519 break;
5520 default:
5521 xmenu();
5522 }
5523 }
5524}
5525#endif /* ADVANCED mode */
5526
5527static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005528is_ide_cdrom_or_tape(const char *device)
5529{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005530 FILE *procf;
5531 char buf[100];
5532 struct stat statbuf;
5533 int is_ide = 0;
5534
5535 /* No device was given explicitly, and we are trying some
5536 likely things. But opening /dev/hdc may produce errors like
5537 "hdc: tray open or drive not ready"
5538 if it happens to be a CD-ROM drive. It even happens that
5539 the process hangs on the attempt to read a music CD.
5540 So try to be careful. This only works since 2.1.73. */
5541
5542 if (strncmp("/dev/hd", device, 7))
5543 return 0;
5544
5545 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5546 procf = fopen(buf, "r");
5547 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5548 is_ide = (!strncmp(buf, "cdrom", 5) ||
5549 !strncmp(buf, "tape", 4));
5550 else
5551 /* Now when this proc file does not exist, skip the
5552 device when it is read-only. */
5553 if (stat(device, &statbuf) == 0)
5554 is_ide = ((statbuf.st_mode & 0222) == 0);
5555
5556 if (procf)
5557 fclose(procf);
5558 return is_ide;
5559}
5560
Rob Landley5527b912006-02-25 03:46:10 +00005561
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005562static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005563try(const char *device, int user_specified)
5564{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005565 int gb;
5566
5567 disk_device = device;
5568 if (setjmp(listingbuf))
5569 return;
5570 if (!user_specified)
5571 if (is_ide_cdrom_or_tape(device))
5572 return;
5573 if ((fd = open(disk_device, type_open)) >= 0) {
5574 gb = get_boot(try_only);
5575 if (gb > 0) { /* I/O error */
5576 close(fd);
5577 } else if (gb < 0) { /* no DOS signature */
5578 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005579 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005580 return;
Rob Landley5527b912006-02-25 03:46:10 +00005581 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005582#ifdef CONFIG_FEATURE_OSF_LABEL
5583 if (btrydev(device) < 0)
5584#endif
5585 fprintf(stderr,
5586 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005587 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005588 close(fd);
5589 } else {
5590 close(fd);
5591 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005592#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005593 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005594 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005595 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005596#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005597 }
5598 } else {
5599 /* Ignore other errors, since we try IDE
5600 and SCSI hard disks which may not be
5601 installed on the system. */
5602 if (errno == EACCES) {
5603 fprintf(stderr, _("Cannot open %s\n"), device);
5604 return;
5605 }
5606 }
5607}
5608
5609/* for fdisk -l: try all things in /proc/partitions
5610 that look like a partition name (do not end in a digit) */
5611static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005612tryprocpt(void)
5613{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005614 FILE *procpt;
5615 char line[100], ptname[100], devname[120], *s;
5616 int ma, mi, sz;
5617
Manuel Novoa III cad53642003-03-19 09:13:01 +00005618 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005619
5620 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005621 if (sscanf(line, " %d %d %d %[^\n ]",
5622 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005623 continue;
5624 for (s = ptname; *s; s++);
5625 if (isdigit(s[-1]))
5626 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005627 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005628 try(devname, 0);
5629 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005630#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005631 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005632#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005633}
5634
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005635#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005636static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005637unknown_command(int c)
5638{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005639 printf(_("%c: unknown command\n"), c);
5640}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005641#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005642
Rob Landleyb73451d2006-02-24 16:29:00 +00005643int fdisk_main(int argc, char **argv)
5644{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005645 int c;
5646#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5647 int optl = 0;
5648#endif
5649#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5650 int opts = 0;
5651#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005652 /*
5653 * Calls:
5654 * fdisk -v
5655 * fdisk -l [-b sectorsize] [-u] device ...
5656 * fdisk -s [partition] ...
5657 * fdisk [-b sectorsize] [-u] device
5658 *
5659 * Options -C, -H, -S set the geometry.
5660 *
5661 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005662 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5663#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5664 "s"
5665#endif
Denis Vlasenko13858992006-10-08 12:49:22 +00005666 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005667 switch (c) {
5668 case 'b':
5669 /* Ugly: this sector size is really per device,
5670 so cannot be combined with multiple disks,
5671 and te same goes for the C/H/S options.
5672 */
Denis Vlasenko13858992006-10-08 12:49:22 +00005673 sector_size = xatoi_u(optarg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005674 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005675 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005676 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005677 sector_offset = 2;
5678 user_set_sector_size = 1;
5679 break;
5680 case 'C':
Denis Vlasenko13858992006-10-08 12:49:22 +00005681 user_cylinders = xatoi_u(optarg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005682 break;
5683 case 'H':
Denis Vlasenko13858992006-10-08 12:49:22 +00005684 user_heads = xatoi_u(optarg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005685 if (user_heads <= 0 || user_heads >= 256)
5686 user_heads = 0;
5687 break;
5688 case 'S':
Denis Vlasenko13858992006-10-08 12:49:22 +00005689 user_sectors = xatoi_u(optarg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005690 if (user_sectors <= 0 || user_sectors >= 64)
5691 user_sectors = 0;
5692 break;
5693 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005694#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005695 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005696#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005697 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005698#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005699 case 's':
5700 opts = 1;
5701 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005702#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005703 case 'u':
5704 display_in_cyl_units = 0;
5705 break;
5706 case 'V':
5707 case 'v':
5708 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5709 return 0;
5710 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005711 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005712 }
5713 }
5714
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005715 if (user_set_sector_size && argc-optind != 1)
5716 printf(_("Warning: the -b (set sector size) option should"
5717 " be used with one specified device\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005718
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005719#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005720 if (optl) {
5721 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005722#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005723 type_open = O_RDONLY;
5724 if (argc > optind) {
5725 int k;
5726#if __GNUC__
5727 /* avoid gcc warning:
5728 variable `k' might be clobbered by `longjmp' */
5729 (void)&k;
5730#endif
5731 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005732 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005733 try(argv[k], 1);
5734 } else {
5735 /* we no longer have default device names */
5736 /* but, we can use /proc/partitions instead */
5737 tryprocpt();
5738 }
5739 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005740#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005741 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005742#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005743
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005744#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005745 if (opts) {
5746 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005747 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005748
5749 nowarn = 1;
5750 type_open = O_RDONLY;
5751
5752 opts = argc - optind;
5753 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005754 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005755
5756 for (j = optind; j < argc; j++) {
5757 disk_device = argv[j];
5758 if ((fd = open(disk_device, type_open)) < 0)
5759 fdisk_fatal(unable_to_open);
5760 if (ioctl(fd, BLKGETSIZE, &size))
5761 fdisk_fatal(ioctl_error);
5762 close(fd);
5763 if (opts == 1)
5764 printf("%ld\n", size/2);
5765 else
5766 printf("%s: %ld\n", argv[j], size/2);
5767 }
5768 return 0;
5769 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005770#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005771
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005772#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005773 if (argc-optind == 1)
5774 disk_device = argv[optind];
5775 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005776 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005777
5778 get_boot(fdisk);
5779
5780#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005781 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005782 /* OSF label, and no DOS label */
5783 printf(_("Detected an OSF/1 disklabel on %s, entering "
5784 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005785 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005786 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005787 /*Why do we do this? It seems to be counter-intuitive*/
5788 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005789 /* If we return we may want to make an empty DOS label? */
5790 }
5791#endif
5792
5793 while (1) {
5794 putchar('\n');
5795 c = tolower(read_char(_("Command (m for help): ")));
5796 switch (c) {
5797 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005798 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005799 toggle_active(get_partition(1, partitions));
5800#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005801 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005802 toggle_sunflags(get_partition(1, partitions),
5803 0x01);
5804#endif
5805#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005806 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005807 sgi_set_bootpartition(
5808 get_partition(1, partitions));
5809#endif
5810 else
5811 unknown_command(c);
5812 break;
5813 case 'b':
5814#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005815 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005816 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005817 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005818 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005819 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005820 printf(_("Boot file unchanged\n"));
5821 else
5822 sgi_set_bootfile(line_ptr);
5823 } else
5824#endif
5825#ifdef CONFIG_FEATURE_OSF_LABEL
5826 bselect();
5827#endif
5828 break;
5829 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005830 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005831 toggle_dos_compatibility_flag();
5832#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005833 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005834 toggle_sunflags(get_partition(1, partitions),
5835 0x10);
5836#endif
5837#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005838 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005839 sgi_set_swappartition(
5840 get_partition(1, partitions));
5841#endif
5842 else
5843 unknown_command(c);
5844 break;
5845 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005846 {
Eric Andersen040f4402003-07-30 08:40:37 +00005847 int j;
5848#ifdef CONFIG_FEATURE_SGI_LABEL
5849 /* If sgi_label then don't use get_existing_partition,
5850 let the user select a partition, since
5851 get_existing_partition() only works for Linux-like
5852 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005853 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005854 j = get_existing_partition(1, partitions);
5855 } else {
5856 j = get_partition(1, partitions);
5857 }
5858#else
5859 j = get_existing_partition(1, partitions);
5860#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005861 if (j >= 0)
5862 delete_partition(j);
5863 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005864 break;
5865 case 'i':
5866#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005867 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005868 create_sgiinfo();
5869 else
5870#endif
5871 unknown_command(c);
5872 case 'l':
5873 list_types(get_sys_types());
5874 break;
5875 case 'm':
5876 menu();
5877 break;
5878 case 'n':
5879 new_partition();
5880 break;
5881 case 'o':
5882 create_doslabel();
5883 break;
5884 case 'p':
5885 list_table(0);
5886 break;
5887 case 'q':
5888 close(fd);
5889 printf("\n");
5890 return 0;
5891 case 's':
5892#ifdef CONFIG_FEATURE_SUN_LABEL
5893 create_sunlabel();
5894#endif
5895 break;
5896 case 't':
5897 change_sysid();
5898 break;
5899 case 'u':
5900 change_units();
5901 break;
5902 case 'v':
5903 verify();
5904 break;
5905 case 'w':
5906 write_table(); /* does not return */
5907 break;
5908#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5909 case 'x':
5910#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005911 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005912 fprintf(stderr,
5913 _("\n\tSorry, no experts menu for SGI "
5914 "partition tables available.\n\n"));
5915 } else
5916#endif
5917
5918 xselect();
5919 break;
5920#endif
5921 default:
5922 unknown_command(c);
5923 menu();
5924 }
5925 }
5926 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005927#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005928}