blob: 310bd555e9224625fa36b1420ef2abd881339744 [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;
1225 }
1226 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1227 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001228}
1229
1230static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001231xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001232{
Rob Landleyb73451d2006-02-24 16:29:00 +00001233 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001234
Rob Landleyb73451d2006-02-24 16:29:00 +00001235 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001236
1237#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001238 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1239 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1240 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1241 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001242#endif
1243
Rob Landleyb73451d2006-02-24 16:29:00 +00001244 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1245 while (1) {
1246 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1247 _("sectors/cylinder"));
1248 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1249 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001250
Rob Landleyb73451d2006-02-24 16:29:00 +00001251 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1252 }
1253 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1254 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1255 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1256 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1257 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1258 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001259
Rob Landleyb73451d2006-02-24 16:29:00 +00001260 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001261}
1262
1263static int
1264xbsd_get_bootstrap (char *path, void *ptr, int size)
1265{
Rob Landleyb73451d2006-02-24 16:29:00 +00001266 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001267
Rob Landleyb73451d2006-02-24 16:29:00 +00001268 if ((fdb = open (path, O_RDONLY)) < 0) {
1269 perror(path);
1270 return 0;
1271 }
1272 if (read(fdb, ptr, size) < 0) {
1273 perror(path);
1274 close(fdb);
1275 return 0;
1276 }
1277 printf(" ... %s\n", path);
1278 close(fdb);
1279 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001280}
1281
1282static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001283sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001284{
Rob Landleyb73451d2006-02-24 16:29:00 +00001285 printf(_("\nSyncing disks.\n"));
1286 sync();
1287 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001288}
1289
1290static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001291xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001292{
Rob Landleyb73451d2006-02-24 16:29:00 +00001293 char *bootdir = BSD_LINUX_BOOTDIR;
1294 char path[MAXPATHLEN];
1295 char *dkbasename;
1296 struct xbsd_disklabel dl;
1297 char *d, *p, *e;
1298 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001299
Rob Landleyb73451d2006-02-24 16:29:00 +00001300 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1301 dkbasename = "sd";
1302 else
1303 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001304
Rob Landleyb73451d2006-02-24 16:29:00 +00001305 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1306 dkbasename, dkbasename, dkbasename);
1307 if (read_line()) {
1308 line_ptr[strlen(line_ptr)-1] = '\0';
1309 dkbasename = line_ptr;
1310 }
1311 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1312 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1313 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001314
Rob Landleyb73451d2006-02-24 16:29:00 +00001315/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1316 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
Mike Frysinger1a540302006-04-16 05:58:21 +00001317 memmove(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001318
Rob Landleyb73451d2006-02-24 16:29:00 +00001319/* The disklabel will be overwritten by 0's from bootxx anyway */
1320 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001321
Rob Landleyb73451d2006-02-24 16:29:00 +00001322 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1323 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001324 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001325 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001326
Rob Landleyb73451d2006-02-24 16:29:00 +00001327 e = d + sizeof(struct xbsd_disklabel);
1328 for (p = d; p < e; p++)
1329 if (*p) {
1330 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1331 exit(EXIT_FAILURE);
1332 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001333
Mike Frysinger1a540302006-04-16 05:58:21 +00001334 memmove(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001335
1336#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001337 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001338#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001339 sector = 0;
1340 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001341#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001342 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001343#endif
1344
Rob Landleyb73451d2006-02-24 16:29:00 +00001345 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1346 fdisk_fatal(unable_to_seek);
1347 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1348 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001349
1350#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001351 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001352#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001353 printf(_("Bootstrap installed on %s.\n"),
1354 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001355#endif
1356
Rob Landleyb73451d2006-02-24 16:29:00 +00001357 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001358}
1359
1360static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001361xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001362{
Rob Landleyb73451d2006-02-24 16:29:00 +00001363 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001364
Rob Landleyb73451d2006-02-24 16:29:00 +00001365 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1366 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001367}
1368
1369static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001370xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001371{
Rob Landleyb73451d2006-02-24 16:29:00 +00001372 char prompt[256];
1373 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001374
Rob Landleyb73451d2006-02-24 16:29:00 +00001375 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1376 do
1377 l = tolower(read_char(prompt));
1378 while (l < 'a' || l > 'a' + max - 1);
1379 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001380}
1381
1382static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001383xbsd_check_new_partition(int *i)
1384{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001385 /* room for more? various BSD flavours have different maxima */
1386 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1387 int t;
1388
1389 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1390 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1391 break;
1392
1393 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001394 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001395 "has been created\n"));
1396 return 0;
1397 }
1398 }
1399
1400 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1401
1402 if (*i >= xbsd_dlabel.d_npartitions)
1403 xbsd_dlabel.d_npartitions = (*i) + 1;
1404
1405 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001406 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001407 return 0;
1408 }
1409
1410 return 1;
1411}
1412
1413static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001414xbsd_list_types(void)
1415{
1416 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001417}
1418
1419static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001420xbsd_dkcksum(struct xbsd_disklabel *lp)
1421{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001422 u_short *start, *end;
1423 u_short sum = 0;
1424
1425 start = (u_short *) lp;
1426 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1427 while (start < end)
1428 sum ^= *start++;
1429 return sum;
1430}
1431
1432static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001433xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1434{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001435 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001436
Rob Landleyb73451d2006-02-24 16:29:00 +00001437 get_geometry();
1438 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001439
Rob Landleyb73451d2006-02-24 16:29:00 +00001440 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001441
Rob Landleyb73451d2006-02-24 16:29:00 +00001442 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1443 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001444 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001445 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001446
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001447#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001448 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001449#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001450 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001451#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001452 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1453 d->d_nsectors = sectors; /* sectors/track */
1454 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1455 d->d_ncylinders = cylinders;
1456 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1457 if (d->d_secpercyl == 0)
1458 d->d_secpercyl = 1; /* avoid segfaults */
1459 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001460
Rob Landleyb73451d2006-02-24 16:29:00 +00001461 d->d_rpm = 3600;
1462 d->d_interleave = 1;
1463 d->d_trackskew = 0;
1464 d->d_cylskew = 0;
1465 d->d_headswitch = 0;
1466 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001467
Rob Landleyb73451d2006-02-24 16:29:00 +00001468 d->d_magic2 = BSD_DISKMAGIC;
1469 d->d_bbsize = BSD_BBSIZE;
1470 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001471
1472#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001473 d->d_npartitions = 4;
1474 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001475 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001476 pp->p_offset = get_start_sect(p);
1477 pp->p_size = get_nr_sects(p);
1478 pp->p_fstype = BSD_FS_UNUSED;
1479 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001480 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001481 pp->p_offset = 0;
1482 pp->p_size = d->d_secperunit;
1483 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001484#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001485 d->d_npartitions = 3;
1486 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001487 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001488 pp->p_offset = 0;
1489 pp->p_size = d->d_secperunit;
1490 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001491#endif
1492
1493 return 1;
1494}
1495
1496/*
1497 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1498 * If it has the right magic, return 1.
1499 */
1500static int
1501xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1502{
1503 int t, sector;
1504
1505 /* p is used only to get the starting sector */
1506#if !defined (__alpha__)
1507 sector = (p ? get_start_sect(p) : 0);
1508#elif defined (__alpha__)
1509 sector = 0;
1510#endif
1511
Rob Landleyb73451d2006-02-24 16:29:00 +00001512 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1513 fdisk_fatal(unable_to_seek);
1514 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1515 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001516
Mike Frysinger1a540302006-04-16 05:58:21 +00001517 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1518 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001519
Rob Landleyb73451d2006-02-24 16:29:00 +00001520 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001521 return 0;
1522
Rob Landleyb73451d2006-02-24 16:29:00 +00001523 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1524 d->d_partitions[t].p_size = 0;
1525 d->d_partitions[t].p_offset = 0;
1526 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001527 }
1528
Rob Landleyb73451d2006-02-24 16:29:00 +00001529 if (d->d_npartitions > BSD_MAXPARTITIONS)
1530 fprintf(stderr, _("Warning: too many partitions "
1531 "(%d, maximum is %d).\n"),
1532 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001533 return 1;
1534}
1535
1536static int
1537xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1538{
Rob Landleyb73451d2006-02-24 16:29:00 +00001539 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001540
1541#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001542 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001543#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001544 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001545#endif
1546
Rob Landleyb73451d2006-02-24 16:29:00 +00001547 d->d_checksum = 0;
1548 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001549
Rob Landleyb73451d2006-02-24 16:29:00 +00001550 /* This is necessary if we want to write the bootstrap later,
1551 otherwise we'd write the old disklabel with the bootstrap.
1552 */
Mike Frysinger1a540302006-04-16 05:58:21 +00001553 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1554 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001555
1556#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001557 alpha_bootblock_checksum (disklabelbuffer);
1558 if (lseek(fd, 0, SEEK_SET) == -1)
1559 fdisk_fatal(unable_to_seek);
1560 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1561 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001562#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001563 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1564 fdisk_fatal(unable_to_seek);
1565 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1566 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001567#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001568 sync_disks();
1569 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001570}
1571
1572
1573#if !defined (__alpha__)
1574static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001575xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001576{
Rob Landleyb73451d2006-02-24 16:29:00 +00001577 switch (linux_type) {
1578 case 0x01: /* DOS 12-bit FAT */
1579 case 0x04: /* DOS 16-bit <32M */
1580 case 0x06: /* DOS 16-bit >=32M */
1581 case 0xe1: /* DOS access */
1582 case 0xe3: /* DOS R/O */
1583 case 0xf2: /* DOS secondary */
1584 return BSD_FS_MSDOS;
1585 case 0x07: /* OS/2 HPFS */
1586 return BSD_FS_HPFS;
1587 default:
1588 return BSD_FS_OTHER;
1589 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001590}
1591
1592static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001593xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001594{
Rob Landleyb73451d2006-02-24 16:29:00 +00001595 int k, i;
1596 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001597
Rob Landleyb73451d2006-02-24 16:29:00 +00001598 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001599
Rob Landleyb73451d2006-02-24 16:29:00 +00001600 if (!xbsd_check_new_partition(&i))
1601 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001602
Rob Landleyb73451d2006-02-24 16:29:00 +00001603 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001604
Rob Landleyb73451d2006-02-24 16:29:00 +00001605 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1606 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1607 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001608}
1609#endif
1610
1611#if defined (__alpha__)
1612
1613#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001614typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001615#endif
1616
1617static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001618alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001619{
Rob Landleyb73451d2006-02-24 16:29:00 +00001620 uint64_t *dp, sum;
1621 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001622
Rob Landleyb73451d2006-02-24 16:29:00 +00001623 dp = (uint64_t *)boot;
1624 sum = 0;
1625 for (i = 0; i < 63; i++)
1626 sum += dp[i];
1627 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001628}
1629#endif /* __alpha__ */
1630
1631#endif /* OSF_LABEL */
1632
1633#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1634static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001635__swap16(unsigned short x)
1636{
Eric Andersenacd244a2002-12-11 03:49:33 +00001637 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001638}
1639
Eric Andersenacd244a2002-12-11 03:49:33 +00001640static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001641__swap32(uint32_t x)
1642{
1643 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001644 ((x & 0xFF00) << 8) |
1645 ((x & 0xFF0000) >> 8) |
1646 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001647}
1648#endif
1649
1650#ifdef CONFIG_FEATURE_SGI_LABEL
1651/*
1652 *
1653 * fdisksgilabel.c
1654 *
1655 * Copyright (C) Andreas Neuper, Sep 1998.
1656 * This file may be modified and redistributed under
1657 * the terms of the GNU Public License.
1658 *
1659 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1660 * Internationalization
1661 */
1662
1663
Rob Landleyb73451d2006-02-24 16:29:00 +00001664static int sgi_other_endian;
1665static int debug;
1666static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001667
1668/*
1669 * only dealing with free blocks here
1670 */
1671
Rob Landleyb73451d2006-02-24 16:29:00 +00001672typedef struct {
1673 unsigned int first;
1674 unsigned int last;
1675} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001676static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1677
1678static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001679setfreelist(int i, unsigned int f, unsigned int l)
1680{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001681 freelist[i].first = f;
1682 freelist[i].last = l;
1683}
1684
1685static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001686add2freelist(unsigned int f, unsigned int l)
1687{
1688 int i;
1689 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001690 if (freelist[i].last == 0)
1691 break;
1692 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001693}
1694
1695static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001696clearfreelist(void)
1697{
Eric Andersen040f4402003-07-30 08:40:37 +00001698 int i;
1699
1700 for (i = 0; i < 17 ; i++)
1701 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001702}
1703
Eric Andersen040f4402003-07-30 08:40:37 +00001704static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001705isinfreelist(unsigned int b)
1706{
Eric Andersen040f4402003-07-30 08:40:37 +00001707 int i;
1708
1709 for (i = 0; i < 17 ; i++)
1710 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001711 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001712 return 0;
1713}
1714 /* return last vacant block of this stride (never 0). */
1715 /* the '>=' is not quite correct, but simplifies the code */
1716/*
1717 * end of free blocks section
1718 */
1719
1720static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001721/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1722/* 0x01 */ { "\x01" "SGI trkrepl" },
1723/* 0x02 */ { "\x02" "SGI secrepl" },
1724/* SGI_SWAP */ { "\x03" "SGI raw" },
1725/* 0x04 */ { "\x04" "SGI bsd" },
1726/* 0x05 */ { "\x05" "SGI sysv" },
1727/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1728/* SGI_EFS */ { "\x07" "SGI efs" },
1729/* 0x08 */ { "\x08" "SGI lvol" },
1730/* 0x09 */ { "\x09" "SGI rlvol" },
1731/* SGI_XFS */ { "\x0a" "SGI xfs" },
1732/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1733/* SGI_XLV */ { "\x0c" "SGI xlv" },
1734/* SGI_XVM */ { "\x0d" "SGI xvm" },
1735/* LINUX_SWAP */ { "\x82" "Linux swap" },
1736/* LINUX_NATIVE */ { "\x83" "Linux native" },
1737/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1738/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1739 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001740};
1741
1742
1743static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001744sgi_get_nsect(void)
1745{
1746 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001747}
1748
1749static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001750sgi_get_ntrks(void)
1751{
1752 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001753}
1754
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001755static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001756two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1757{
1758 int i = 0;
1759 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001760
Rob Landleyb73451d2006-02-24 16:29:00 +00001761 size /= sizeof(unsigned int);
1762 for (i = 0; i < size; i++)
1763 sum -= SGI_SSWAP32(base[i]);
1764 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001765}
1766
1767static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001768check_sgi_label(void)
1769{
1770 if (sizeof(sgilabel) > 512) {
1771 fprintf(stderr,
1772 _("According to MIPS Computer Systems, Inc the "
1773 "Label must not contain more than 512 bytes\n"));
1774 exit(1);
1775 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001776
Rob Landleyb73451d2006-02-24 16:29:00 +00001777 if (sgilabel->magic != SGI_LABEL_MAGIC
1778 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001779 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001780 return 0;
1781 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001782
Rob Landleyb73451d2006-02-24 16:29:00 +00001783 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1784 /*
1785 * test for correct checksum
1786 */
1787 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1788 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001789 fprintf(stderr,
1790 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001791 }
1792 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001793 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001794 partitions = 16;
1795 sgi_volumes = 15;
1796 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001797}
1798
Eric Andersen040f4402003-07-30 08:40:37 +00001799static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001800sgi_get_start_sector(int i)
1801{
1802 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001803}
1804
Eric Andersen040f4402003-07-30 08:40:37 +00001805static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001806sgi_get_num_sectors(int i)
1807{
1808 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001809}
1810
1811static int
Eric Andersen040f4402003-07-30 08:40:37 +00001812sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001813{
Rob Landleyb73451d2006-02-24 16:29:00 +00001814 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001815}
1816
1817static int
1818sgi_get_bootpartition(void)
1819{
Rob Landleyb73451d2006-02-24 16:29:00 +00001820 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001821}
1822
1823static int
1824sgi_get_swappartition(void)
1825{
Rob Landleyb73451d2006-02-24 16:29:00 +00001826 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001827}
1828
1829static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001830sgi_list_table(int xtra)
1831{
1832 int i, w, wd;
1833 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001834
Rob Landleyb73451d2006-02-24 16:29:00 +00001835 if(xtra) {
1836 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1837 "%d cylinders, %d physical cylinders\n"
1838 "%d extra sects/cyl, interleave %d:1\n"
1839 "%s\n"
1840 "Units = %s of %d * 512 bytes\n\n"),
1841 disk_device, heads, sectors, cylinders,
1842 SGI_SSWAP16(sgiparam.pcylcount),
1843 SGI_SSWAP16(sgiparam.sparecyl),
1844 SGI_SSWAP16(sgiparam.ilfact),
1845 (char *)sgilabel,
1846 str_units(PLURAL), units_per_sector);
1847 } else {
1848 printf( _("\nDisk %s (SGI disk label): "
1849 "%d heads, %d sectors, %d cylinders\n"
1850 "Units = %s of %d * 512 bytes\n\n"),
1851 disk_device, heads, sectors, cylinders,
1852 str_units(PLURAL), units_per_sector );
1853 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001854
Rob Landleyb73451d2006-02-24 16:29:00 +00001855 w = strlen(disk_device);
1856 wd = strlen(_("Device"));
1857 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001858 w = wd;
1859
Rob Landleyb73451d2006-02-24 16:29:00 +00001860 printf(_("----- partitions -----\n"
1861 "Pt# %*s Info Start End Sectors Id System\n"),
1862 w + 2, _("Device"));
1863 for (i = 0 ; i < partitions; i++) {
1864 if( sgi_get_num_sectors(i) || debug ) {
1865 uint32_t start = sgi_get_start_sector(i);
1866 uint32_t len = sgi_get_num_sectors(i);
1867 kpi++; /* only count nonempty partitions */
1868 printf(
1869 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1870/* fdisk part number */ i+1,
1871/* device */ partname(disk_device, kpi, w+3),
1872/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1873/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1874/* start */ (long) scround(start),
1875/* end */ (long) scround(start+len)-1,
1876/* no odd flag on end */(long) len,
1877/* type id */ sgi_get_sysid(i),
1878/* type name */ partition_type(sgi_get_sysid(i)));
1879 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001880 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001881 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1882 "----- Directory Entries -----\n"),
1883 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001884 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001885 if (sgilabel->directory[i].vol_file_size) {
1886 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1887 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1888 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001889
Rob Landleyb73451d2006-02-24 16:29:00 +00001890 printf(_("%2d: %-10s sector%5u size%8u\n"),
1891 i, (char*)name, (unsigned int) start, (unsigned int) len);
1892 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001893 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001894}
1895
1896static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001897sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001898{
Rob Landleyb73451d2006-02-24 16:29:00 +00001899 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001900}
1901
Eric Andersen040f4402003-07-30 08:40:37 +00001902static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001903sgi_get_lastblock(void)
1904{
1905 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001906}
1907
1908static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001909sgi_set_swappartition(int i)
1910{
1911 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001912}
1913
1914static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001915sgi_check_bootfile(const char* aFile)
1916{
1917 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1918 printf(_("\nInvalid Bootfile!\n"
1919 "\tThe bootfile must be an absolute non-zero pathname,\n"
1920 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1921 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001922 } else {
1923 if (strlen(aFile) > 16) {
1924 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001925 "16 bytes maximum.\n"));
1926 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001927 } else {
1928 if (aFile[0] != '/') {
1929 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001930 "fully qualified pathname.\n"));
1931 return 0;
1932 }
Eric Andersen040f4402003-07-30 08:40:37 +00001933 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001934 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001935 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001936 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1937 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001938 /* filename is correct and did change */
1939 return 1;
1940 }
1941 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001942}
1943
1944static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001945sgi_get_bootfile(void)
1946{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001947 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001948}
1949
1950static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001951sgi_set_bootfile(const char* aFile)
1952{
1953 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001954
Rob Landleyb73451d2006-02-24 16:29:00 +00001955 if (sgi_check_bootfile(aFile)) {
1956 while (i < 16) {
1957 if ((aFile[i] != '\n') /* in principle caught again by next line */
1958 && (strlen(aFile) > i))
1959 sgilabel->boot_file[i] = aFile[i];
1960 else
1961 sgilabel->boot_file[i] = 0;
1962 i++;
1963 }
1964 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001965 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001966}
1967
1968static void
1969create_sgiinfo(void)
1970{
Rob Landleyb73451d2006-02-24 16:29:00 +00001971 /* I keep SGI's habit to write the sgilabel to the second block */
1972 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1973 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
Rob Landley11c7a7b2006-06-25 22:39:24 +00001974 strcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001975}
1976
Eric Andersen040f4402003-07-30 08:40:37 +00001977static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001978
1979static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001980sgi_write_table(void)
1981{
1982 sgilabel->csum = 0;
1983 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1984 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1985 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00001986 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00001987
1988 if (lseek(fd, 0, SEEK_SET) < 0)
1989 fdisk_fatal(unable_to_seek);
1990 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
1991 fdisk_fatal(unable_to_write);
1992 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
1993 /*
1994 * keep this habit of first writing the "sgilabel".
1995 * I never tested whether it works without (AN 981002).
1996 */
1997 sgiinfo *info = fill_sgiinfo();
1998 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
1999 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2000 fdisk_fatal(unable_to_seek);
2001 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2002 fdisk_fatal(unable_to_write);
2003 free(info);
2004 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002005}
2006
2007static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002008compare_start(int *x, int *y)
2009{
2010 /*
2011 * sort according to start sectors
2012 * and prefers largest partition:
2013 * entry zero is entire disk entry
2014 */
2015 unsigned int i = *x;
2016 unsigned int j = *y;
2017 unsigned int a = sgi_get_start_sector(i);
2018 unsigned int b = sgi_get_start_sector(j);
2019 unsigned int c = sgi_get_num_sectors(i);
2020 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002021
Rob Landleyb73451d2006-02-24 16:29:00 +00002022 if (a == b)
2023 return (d > c) ? 1 : (d == c) ? 0 : -1;
2024 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002025}
2026
2027
2028static int
Eric Andersen040f4402003-07-30 08:40:37 +00002029verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002030{
Rob Landleyb73451d2006-02-24 16:29:00 +00002031 int Index[16]; /* list of valid partitions */
2032 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2033 int entire = 0, i = 0;
2034 unsigned int start = 0;
2035 long long gap = 0; /* count unused blocks */
2036 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002037
Rob Landleyb73451d2006-02-24 16:29:00 +00002038 clearfreelist();
2039 for (i = 0; i < 16; i++) {
2040 if (sgi_get_num_sectors(i) != 0) {
2041 Index[sortcount++] = i;
2042 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2043 if (entire++ == 1) {
2044 if (verbose)
2045 printf(_("More than one entire disk entry present.\n"));
2046 }
2047 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002048 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002049 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002050 if (sortcount == 0) {
2051 if (verbose)
2052 printf(_("No partitions defined\n"));
2053 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2054 }
2055 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2056 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2057 if ((Index[0] != 10) && verbose)
2058 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2059 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2060 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002061 "at block 0,\n"
2062 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002063 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002064 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002065 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2066 printf(_("The entire disk partition is only %d diskblock large,\n"
2067 "but the disk is %d diskblocks long.\n"),
2068 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002069 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002070 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002071 if (verbose)
2072 printf(_("One Partition (#11) should cover the entire disk.\n"));
2073 if (debug > 2)
2074 printf("sysid=%d\tpartition=%d\n",
2075 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002076 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002077 for (i = 1, start = 0; i < sortcount; i++) {
2078 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2079
2080 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2081 if (debug) /* I do not understand how some disks fulfil it */
2082 if (verbose)
2083 printf(_("Partition %d does not start on cylinder boundary.\n"),
2084 Index[i]+1);
2085 }
2086 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2087 if (debug) /* I do not understand how some disks fulfil it */
2088 if (verbose)
2089 printf(_("Partition %d does not end on cylinder boundary.\n"),
2090 Index[i]+1);
2091 }
2092 /* We cannot handle several "entire disk" entries. */
2093 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2094 if (start > sgi_get_start_sector(Index[i])) {
2095 if (verbose)
2096 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2097 Index[i-1]+1, Index[i]+1,
2098 start - sgi_get_start_sector(Index[i]));
2099 if (gap > 0) gap = -gap;
2100 if (gap == 0) gap = -1;
2101 }
2102 if (start < sgi_get_start_sector(Index[i])) {
2103 if (verbose)
2104 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2105 sgi_get_start_sector(Index[i]) - start,
2106 start, sgi_get_start_sector(Index[i])-1);
2107 gap += sgi_get_start_sector(Index[i]) - start;
2108 add2freelist(start, sgi_get_start_sector(Index[i]));
2109 }
2110 start = sgi_get_start_sector(Index[i])
2111 + sgi_get_num_sectors(Index[i]);
2112 if (debug > 1) {
2113 if (verbose)
2114 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2115 sgi_get_start_sector(Index[i]),
2116 sgi_get_num_sectors(Index[i]),
2117 sgi_get_sysid(Index[i]));
2118 }
2119 }
2120 if (start < lastblock) {
2121 if (verbose)
2122 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2123 lastblock - start, start, lastblock-1);
2124 gap += lastblock - start;
2125 add2freelist(start, lastblock);
2126 }
2127 /*
2128 * Done with arithmetics
2129 * Go for details now
2130 */
2131 if (verbose) {
2132 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2133 printf(_("\nThe boot partition does not exist.\n"));
2134 }
2135 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2136 printf(_("\nThe swap partition does not exist.\n"));
2137 } else {
2138 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2139 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2140 printf(_("\nThe swap partition has no swap type.\n"));
2141 }
2142 if (sgi_check_bootfile("/unix"))
2143 printf(_("\tYou have chosen an unusual boot file name.\n"));
2144 }
2145 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002146}
2147
2148static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002149sgi_gaps(void)
2150{
2151 /*
2152 * returned value is:
2153 * = 0 : disk is properly filled to the rim
2154 * < 0 : there is an overlap
2155 * > 0 : there is still some vacant space
2156 */
2157 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002158}
2159
2160static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002161sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002162{
Rob Landleyb73451d2006-02-24 16:29:00 +00002163 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2164 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2165 return;
2166 }
2167 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2168 && (sgi_get_start_sector(i) < 1) ) {
2169 read_chars(
2170 _("It is highly recommended that the partition at offset 0\n"
2171 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2172 "retrieve from its directory standalone tools like sash and fx.\n"
2173 "Only the \"SGI volume\" entire disk section may violate this.\n"
2174 "Type YES if you are sure about tagging this partition differently.\n"));
2175 if (strcmp(line_ptr, _("YES\n")))
2176 return;
2177 }
2178 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002179}
2180
2181/* returns partition index of first entry marked as entire disk */
2182static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002183sgi_entire(void)
2184{
2185 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002186
Rob Landleyb73451d2006-02-24 16:29:00 +00002187 for (i = 0; i < 16; i++)
2188 if (sgi_get_sysid(i) == SGI_VOLUME)
2189 return i;
2190 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002191}
2192
2193static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002194sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2195{
2196 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2197 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2198 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2199 set_changed(i);
2200 if (sgi_gaps() < 0) /* rebuild freelist */
2201 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002202}
2203
2204static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002205sgi_set_entire(void)
2206{
2207 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002208
Rob Landleyb73451d2006-02-24 16:29:00 +00002209 for (n = 10; n < partitions; n++) {
2210 if(!sgi_get_num_sectors(n) ) {
2211 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2212 break;
2213 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002214 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002215}
2216
2217static void
2218sgi_set_volhdr(void)
2219{
Rob Landleyb73451d2006-02-24 16:29:00 +00002220 int n;
2221
2222 for (n = 8; n < partitions; n++) {
2223 if (!sgi_get_num_sectors(n)) {
2224 /*
2225 * 5 cylinders is an arbitrary value I like
2226 * IRIX 5.3 stored files in the volume header
2227 * (like sash, symmon, fx, ide) with ca. 3200
2228 * sectors.
2229 */
2230 if (heads * sectors * 5 < sgi_get_lastblock())
2231 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2232 break;
2233 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002234 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002235}
2236
2237static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002238sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002239{
Rob Landleyb73451d2006-02-24 16:29:00 +00002240 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002241}
2242
2243static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002244sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002245{
Rob Landleyb73451d2006-02-24 16:29:00 +00002246 char mesg[256];
2247 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002248
Rob Landleyb73451d2006-02-24 16:29:00 +00002249 if (n == 10) {
2250 sys = SGI_VOLUME;
2251 } else if (n == 8) {
2252 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002253 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002254 if(sgi_get_num_sectors(n)) {
2255 printf(_("Partition %d is already defined. Delete "
2256 "it before re-adding it.\n"), n + 1);
2257 return;
2258 }
2259 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2260 printf(_("Attempting to generate entire disk entry automatically.\n"));
2261 sgi_set_entire();
2262 sgi_set_volhdr();
2263 }
2264 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2265 printf(_("The entire disk is already covered with partitions.\n"));
2266 return;
2267 }
2268 if (sgi_gaps() < 0) {
2269 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2270 return;
2271 }
2272 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2273 while (1) {
2274 if(sys == SGI_VOLUME) {
2275 last = sgi_get_lastblock();
2276 first = read_int(0, 0, last-1, 0, mesg);
2277 if (first != 0) {
2278 printf(_("It is highly recommended that eleventh partition\n"
2279 "covers the entire disk and is of type `SGI volume'\n"));
2280 }
2281 } else {
2282 first = freelist[0].first;
2283 last = freelist[0].last;
2284 first = read_int(scround(first), scround(first), scround(last)-1,
2285 0, mesg);
2286 }
2287 if (display_in_cyl_units)
2288 first *= units_per_sector;
2289 else
2290 first = first; /* align to cylinder if you know how ... */
2291 if(!last )
2292 last = isinfreelist(first);
2293 if(last == 0) {
2294 printf(_("You will get a partition overlap on the disk. "
2295 "Fix it first!\n"));
2296 } else
2297 break;
2298 }
2299 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2300 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2301 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002302 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002303 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002304 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002305 last = last; /* align to cylinder if You know how ... */
2306 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2307 printf(_("It is highly recommended that eleventh partition\n"
2308 "covers the entire disk and is of type `SGI volume'\n"));
2309 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002310}
2311
Eric Andersen040f4402003-07-30 08:40:37 +00002312#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002313static void
2314create_sgilabel(void)
2315{
Rob Landleyb73451d2006-02-24 16:29:00 +00002316 struct hd_geometry geometry;
2317 struct {
2318 unsigned int start;
2319 unsigned int nsect;
2320 int sysid;
2321 } old[4];
2322 int i = 0;
2323 long longsectors; /* the number of sectors on the device */
2324 int res; /* the result from the ioctl */
2325 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002326
Rob Landleyb73451d2006-02-24 16:29:00 +00002327 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002328
Rob Landleyb73451d2006-02-24 16:29:00 +00002329 fprintf( stderr,
2330 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2331 "until you decide to write them. After that, of course, the previous\n"
2332 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002333
Rob Landley2c39eee2006-05-05 16:54:40 +00002334 sgi_other_endian = (BB_LITTLE_ENDIAN);
Rob Landleyb73451d2006-02-24 16:29:00 +00002335 res = ioctl(fd, BLKGETSIZE, &longsectors);
2336 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2337 heads = geometry.heads;
2338 sectors = geometry.sectors;
2339 if (res == 0) {
2340 /* the get device size ioctl was successful */
2341 cylinders = longsectors / (heads * sectors);
2342 cylinders /= sec_fac;
2343 } else {
2344 /* otherwise print error and use truncated version */
2345 cylinders = geometry.cylinders;
2346 fprintf(stderr,
2347 _("Warning: BLKGETSIZE ioctl failed on %s. "
2348 "Using geometry cylinder value of %d.\n"
2349 "This value may be truncated for devices"
2350 " > 33.8 GB.\n"), disk_device, cylinders);
2351 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002352 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002353 for (i = 0; i < 4; i++) {
2354 old[i].sysid = 0;
2355 if (valid_part_table_flag(MBRbuffer)) {
2356 if(get_part_table(i)->sys_ind) {
2357 old[i].sysid = get_part_table(i)->sys_ind;
2358 old[i].start = get_start_sect(get_part_table(i));
2359 old[i].nsect = get_nr_sects(get_part_table(i));
2360 printf(_("Trying to keep parameters of partition %d.\n"), i);
2361 if (debug)
2362 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2363 old[i].sysid, old[i].start, old[i].nsect);
2364 }
2365 }
2366 }
Eric Andersen040f4402003-07-30 08:40:37 +00002367
Rob Landleyb73451d2006-02-24 16:29:00 +00002368 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2369 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2370 sgilabel->boot_part = SGI_SSWAP16(0);
2371 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002372
Rob Landleyb73451d2006-02-24 16:29:00 +00002373 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2374 memset(sgilabel->boot_file, 0, 16);
2375 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002376
Rob Landleyb73451d2006-02-24 16:29:00 +00002377 sgilabel->devparam.skew = (0);
2378 sgilabel->devparam.gap1 = (0);
2379 sgilabel->devparam.gap2 = (0);
2380 sgilabel->devparam.sparecyl = (0);
2381 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2382 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2383 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002384 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002385 sgilabel->devparam.cmd_tag_queue_depth = (0);
2386 sgilabel->devparam.unused0 = (0);
2387 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2388 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002389 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002390 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2391 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2392 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002393 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002394 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2395 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2396 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2397 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2398 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2399 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2400 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2401 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2402 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2403 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2404 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002405 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002406 partitions = 16;
2407 sgi_volumes = 15;
2408 sgi_set_entire();
2409 sgi_set_volhdr();
2410 for (i = 0; i < 4; i++) {
2411 if(old[i].sysid) {
2412 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2413 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002414 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002415}
2416
2417static void
2418sgi_set_xcyl(void)
2419{
Rob Landleyb73451d2006-02-24 16:29:00 +00002420 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002421}
Eric Andersen040f4402003-07-30 08:40:37 +00002422#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002423
2424/* _____________________________________________________________
2425 */
2426
Eric Andersen040f4402003-07-30 08:40:37 +00002427static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002428fill_sgiinfo(void)
2429{
Rob Landleyb73451d2006-02-24 16:29:00 +00002430 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002431
Rob Landleyb73451d2006-02-24 16:29:00 +00002432 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2433 info->b1 = SGI_SSWAP32(-1);
2434 info->b2 = SGI_SSWAP16(-1);
2435 info->b3 = SGI_SSWAP16(1);
2436 /* You may want to replace this string !!!!!!! */
2437 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2438 strcpy( (char*)info->serial, "0000" );
2439 info->check1816 = SGI_SSWAP16(18*256 +16 );
2440 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2441 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002442}
2443#endif /* SGI_LABEL */
2444
2445
2446#ifdef CONFIG_FEATURE_SUN_LABEL
2447/*
2448 * fdisksunlabel.c
2449 *
2450 * I think this is mostly, or entirely, due to
2451 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2452 *
2453 * Merged with fdisk for other architectures, aeb, June 1998.
2454 *
2455 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2456 * Internationalization
2457 */
2458
2459
Rob Landleyb73451d2006-02-24 16:29:00 +00002460static int sun_other_endian;
2461static int scsi_disk;
2462static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002463
2464#ifndef IDE0_MAJOR
2465#define IDE0_MAJOR 3
2466#endif
2467#ifndef IDE1_MAJOR
2468#define IDE1_MAJOR 22
2469#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002470
Rob Landleyb73451d2006-02-24 16:29:00 +00002471static void
2472guess_device_type(void)
2473{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002474 struct stat bootstat;
2475
Rob Landleyb73451d2006-02-24 16:29:00 +00002476 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002477 scsi_disk = 0;
2478 floppy = 0;
2479 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002480 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2481 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002482 scsi_disk = 0;
2483 floppy = 0;
2484 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002485 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002486 scsi_disk = 0;
2487 floppy = 1;
2488 } else {
2489 scsi_disk = 1;
2490 floppy = 0;
2491 }
2492}
2493
2494static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002495 { "\x00" "Empty" }, /* 0 */
2496 { "\x01" "Boot" }, /* 1 */
2497 { "\x02" "SunOS root" }, /* 2 */
2498 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2499 { "\x04" "SunOS usr" }, /* 4 */
2500 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2501 { "\x06" "SunOS stand" }, /* 6 */
2502 { "\x07" "SunOS var" }, /* 7 */
2503 { "\x08" "SunOS home" }, /* 8 */
2504 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2505 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2506 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002507/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002508 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2509 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002510};
2511
2512
2513static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002514set_sun_partition(int i, uint start, uint stop, int sysid)
2515{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002516 sunlabel->infos[i].id = sysid;
2517 sunlabel->partitions[i].start_cylinder =
2518 SUN_SSWAP32(start / (heads * sectors));
2519 sunlabel->partitions[i].num_sectors =
2520 SUN_SSWAP32(stop - start);
2521 set_changed(i);
2522}
2523
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002524static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002525check_sun_label(void)
2526{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002527 unsigned short *ush;
2528 int csum;
2529
Rob Landleyb73451d2006-02-24 16:29:00 +00002530 if (sunlabel->magic != SUN_LABEL_MAGIC
2531 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002532 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002533 sun_other_endian = 0;
2534 return 0;
2535 }
2536 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2537 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2538 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2539 if (csum) {
2540 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2541 "Probably you'll have to set all the values,\n"
2542 "e.g. heads, sectors, cylinders and partitions\n"
2543 "or force a fresh label (s command in main menu)\n"));
2544 } else {
2545 heads = SUN_SSWAP16(sunlabel->ntrks);
2546 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2547 sectors = SUN_SSWAP16(sunlabel->nsect);
2548 }
2549 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002550 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002551 partitions = 8;
2552 return 1;
2553}
2554
2555static const struct sun_predefined_drives {
2556 const char *vendor;
2557 const char *model;
2558 unsigned short sparecyl;
2559 unsigned short ncyl;
2560 unsigned short nacyl;
2561 unsigned short pcylcount;
2562 unsigned short ntrks;
2563 unsigned short nsect;
2564 unsigned short rspeed;
2565} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002566 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2567 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2568 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2569 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2570 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2571 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2572 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2573 { "","SUN0104",1,974,2,1019,6,35,3662},
2574 { "","SUN0207",4,1254,2,1272,9,36,3600},
2575 { "","SUN0327",3,1545,2,1549,9,46,3600},
2576 { "","SUN0340",0,1538,2,1544,6,72,4200},
2577 { "","SUN0424",2,1151,2,2500,9,80,4400},
2578 { "","SUN0535",0,1866,2,2500,7,80,5400},
2579 { "","SUN0669",5,1614,2,1632,15,54,3600},
2580 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2581 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2582 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2583 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2584 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002585};
2586
2587static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002588sun_autoconfigure_scsi(void)
2589{
2590 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002591
2592#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002593 unsigned int id[2];
2594 char buffer[2048];
2595 char buffer2[2048];
2596 FILE *pfd;
2597 char *vendor;
2598 char *model;
2599 char *q;
2600 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002601
Rob Landleyb73451d2006-02-24 16:29:00 +00002602 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2603 sprintf(buffer,
2604 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00002605 /* This is very wrong (works only if you have one HBA),
2606 but I haven't found a way how to get hostno
2607 from the current kernel */
2608 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00002609 (id[0]>>16) & 0xff,
2610 id[0] & 0xff,
2611 (id[0]>>8) & 0xff
2612 );
2613 pfd = fopen("/proc/scsi/scsi","r");
2614 if (pfd) {
2615 while (fgets(buffer2, 2048, pfd)) {
2616 if (!strcmp(buffer, buffer2)) {
2617 if (fgets(buffer2,2048,pfd)) {
2618 q = strstr(buffer2,"Vendor: ");
2619 if (q) {
2620 q += 8;
2621 vendor = q;
2622 q = strstr(q," ");
2623 *q++ = 0; /* truncate vendor name */
2624 q = strstr(q,"Model: ");
2625 if (q) {
2626 *q = 0;
2627 q += 7;
2628 model = q;
2629 q = strstr(q," Rev: ");
2630 if (q) {
2631 *q = 0;
2632 for (i = 0; i < SIZE(sun_drives); i++) {
2633 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2634 continue;
2635 if (!strstr(model, sun_drives[i].model))
2636 continue;
2637 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2638 p = sun_drives + i;
2639 break;
2640 }
2641 }
2642 }
2643 }
2644 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002645 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002646 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002647 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002648 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002649 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002650 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002651#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002652 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002653}
2654
Rob Landleyb73451d2006-02-24 16:29:00 +00002655static void
2656create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002657{
2658 struct hd_geometry geometry;
2659 unsigned int ndiv;
2660 int i;
2661 unsigned char c;
2662 const struct sun_predefined_drives *p = NULL;
2663
2664 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002665 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2666 "until you decide to write them. After that, of course, the previous\n"
2667 "content won't be recoverable.\n\n"));
Rob Landley2c39eee2006-05-05 16:54:40 +00002668 sun_other_endian = BB_LITTLE_ENDIAN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002669 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2670 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2671 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002672 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002673 " ? auto configure\n"
2674 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002675 for (i = 0; i < SIZE(sun_drives); i++) {
2676 printf(" %c %s%s%s\n",
2677 i + 'a', sun_drives[i].vendor,
2678 (*sun_drives[i].vendor) ? " " : "",
2679 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002680 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002681 while (1) {
2682 c = read_char(_("Select type (? for auto, 0 for custom): "));
2683 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2684 p = sun_drives + c - 'a';
2685 break;
2686 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2687 p = sun_drives + c - 'A';
2688 break;
2689 } else if (c == '0') {
2690 break;
2691 } else if (c == '?' && scsi_disk) {
2692 p = sun_autoconfigure_scsi();
2693 if (!p)
2694 printf(_("Autoconfigure failed.\n"));
2695 else
2696 break;
2697 }
2698 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002699 }
2700 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002701 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2702 heads = geometry.heads;
2703 sectors = geometry.sectors;
2704 cylinders = geometry.cylinders;
2705 } else {
2706 heads = 0;
2707 sectors = 0;
2708 cylinders = 0;
2709 }
2710 if (floppy) {
2711 sunlabel->nacyl = 0;
2712 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2713 sunlabel->rspeed = SUN_SSWAP16(300);
2714 sunlabel->ilfact = SUN_SSWAP16(1);
2715 sunlabel->sparecyl = 0;
2716 } else {
2717 heads = read_int(1,heads,1024,0,_("Heads"));
2718 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002719 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002720 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002721 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002722 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2723 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2724 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2725 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2726 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2727 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2728 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002729 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002730 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2731 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2732 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2733 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2734 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2735 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2736 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2737 sunlabel->ilfact = SUN_SSWAP16(1);
2738 cylinders = p->ncyl;
2739 heads = p->ntrks;
2740 sectors = p->nsect;
2741 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002742 }
2743
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002744 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002745 "%s%s%s cyl %d alt %d hd %d sec %d",
2746 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2747 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002748 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2749
2750 sunlabel->ntrks = SUN_SSWAP16(heads);
2751 sunlabel->nsect = SUN_SSWAP16(sectors);
2752 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2753 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002754 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002755 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002756 if (cylinders * heads * sectors >= 150 * 2048) {
2757 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2758 } else
2759 ndiv = cylinders * 2 / 3;
2760 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2761 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2762 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002763 }
2764 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2765 {
2766 unsigned short *ush = (unsigned short *)sunlabel;
2767 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002768 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002769 csum ^= *ush++;
2770 sunlabel->csum = csum;
2771 }
2772
2773 set_all_unchanged();
2774 set_changed(0);
2775 get_boot(create_empty_sun);
2776}
2777
2778static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002779toggle_sunflags(int i, unsigned char mask)
2780{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002781 if (sunlabel->infos[i].flags & mask)
2782 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002783 else
2784 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002785 set_changed(i);
2786}
2787
2788static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002789fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2790{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002791 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002792
2793 *start = 0;
2794 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002795 for (i = 0; i < partitions; i++) {
2796 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002797 && sunlabel->infos[i].id
2798 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002799 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2800 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2801 if (continuous) {
2802 if (starts[i] == *start)
2803 *start += lens[i];
2804 else if (starts[i] + lens[i] >= *stop)
2805 *stop = starts[i];
2806 else
2807 continuous = 0;
2808 /* There will be probably more gaps
2809 than one, so lets check afterwards */
2810 }
2811 } else {
2812 starts[i] = 0;
2813 lens[i] = 0;
2814 }
2815 }
2816}
2817
2818static uint *verify_sun_starts;
2819
2820static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002821verify_sun_cmp(int *a, int *b)
2822{
2823 if (*a == -1) return 1;
2824 if (*b == -1) return -1;
2825 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2826 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002827}
2828
2829static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002830verify_sun(void)
2831{
2832 uint starts[8], lens[8], start, stop;
2833 int i,j,k,starto,endo;
2834 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002835
Rob Landleyb73451d2006-02-24 16:29:00 +00002836 verify_sun_starts = starts;
2837 fetch_sun(starts,lens,&start,&stop);
2838 for (k = 0; k < 7; k++) {
2839 for (i = 0; i < 8; i++) {
2840 if (k && (lens[i] % (heads * sectors))) {
2841 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002842 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002843 if (lens[i]) {
2844 for (j = 0; j < i; j++)
2845 if (lens[j]) {
2846 if (starts[j] == starts[i]+lens[i]) {
2847 starts[j] = starts[i]; lens[j] += lens[i];
2848 lens[i] = 0;
2849 } else if (starts[i] == starts[j]+lens[j]){
2850 lens[j] += lens[i];
2851 lens[i] = 0;
2852 } else if (!k) {
2853 if (starts[i] < starts[j]+lens[j]
2854 && starts[j] < starts[i]+lens[i]) {
2855 starto = starts[i];
2856 if (starts[j] > starto)
2857 starto = starts[j];
2858 endo = starts[i]+lens[i];
2859 if (starts[j]+lens[j] < endo)
2860 endo = starts[j]+lens[j];
2861 printf(_("Partition %d overlaps with others in "
2862 "sectors %d-%d\n"), i+1, starto, endo);
2863 }
2864 }
2865 }
2866 }
2867 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002868 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002869 for (i = 0; i < 8; i++) {
2870 if (lens[i])
2871 array[i] = i;
2872 else
2873 array[i] = -1;
2874 }
2875 qsort(array,SIZE(array),sizeof(array[0]),
2876 (int (*)(const void *,const void *)) verify_sun_cmp);
2877 if (array[0] == -1) {
2878 printf(_("No partitions defined\n"));
2879 return;
2880 }
2881 stop = cylinders * heads * sectors;
2882 if (starts[array[0]])
2883 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2884 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2885 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2886 }
2887 start = starts[array[i]] + lens[array[i]];
2888 if (start < stop)
2889 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002890}
2891
2892static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002893add_sun_partition(int n, int sys)
2894{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002895 uint start, stop, stop2;
2896 uint starts[8], lens[8];
2897 int whole_disk = 0;
2898
2899 char mesg[256];
2900 int i, first, last;
2901
2902 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2903 printf(_("Partition %d is already defined. Delete "
2904 "it before re-adding it.\n"), n + 1);
2905 return;
2906 }
2907
2908 fetch_sun(starts,lens,&start,&stop);
2909 if (stop <= start) {
2910 if (n == 2)
2911 whole_disk = 1;
2912 else {
2913 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002914 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002915 return;
2916 }
2917 }
2918 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002919 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002920 if (whole_disk)
2921 first = read_int(0, 0, 0, 0, mesg);
2922 else
2923 first = read_int(scround(start), scround(stop)+1,
2924 scround(stop), 0, mesg);
2925 if (display_in_cyl_units)
2926 first *= units_per_sector;
2927 else
2928 /* Starting sector has to be properly aligned */
2929 first = (first + heads * sectors - 1) / (heads * sectors);
2930 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002931 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002932It is highly recommended that the third partition covers the whole disk\n\
2933and is of type `Whole disk'\n");
2934 /* ewt asks to add: "don't start a partition at cyl 0"
2935 However, edmundo@rano.demon.co.uk writes:
2936 "In addition to having a Sun partition table, to be able to
2937 boot from the disc, the first partition, /dev/sdX1, must
2938 start at cylinder 0. This means that /dev/sdX1 contains
2939 the partition table and the boot block, as these are the
2940 first two sectors of the disc. Therefore you must be
2941 careful what you use /dev/sdX1 for. In particular, you must
2942 not use a partition starting at cylinder 0 for Linux swap,
2943 as that would overwrite the partition table and the boot
2944 block. You may, however, use such a partition for a UFS
2945 or EXT2 file system, as these file systems leave the first
2946 1024 bytes undisturbed. */
2947 /* On the other hand, one should not use partitions
2948 starting at block 0 in an md, or the label will
2949 be trashed. */
2950 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002951 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002952 break;
2953 if (i < partitions && !whole_disk) {
2954 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002955 whole_disk = 1;
2956 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002957 }
2958 printf(_("Sector %d is already allocated\n"), first);
2959 } else
2960 break;
2961 }
2962 stop = cylinders * heads * sectors;
2963 stop2 = stop;
2964 for (i = 0; i < partitions; i++) {
2965 if (starts[i] > first && starts[i] < stop)
2966 stop = starts[i];
2967 }
2968 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002969 _("Last %s or +size or +sizeM or +sizeK"),
2970 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002971 if (whole_disk)
2972 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2973 0, mesg);
2974 else if (n == 2 && !first)
2975 last = read_int(scround(first), scround(stop2), scround(stop2),
2976 scround(first), mesg);
2977 else
2978 last = read_int(scround(first), scround(stop), scround(stop),
2979 scround(first), mesg);
2980 if (display_in_cyl_units)
2981 last *= units_per_sector;
2982 if (n == 2 && !first) {
2983 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002984 whole_disk = 1;
2985 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002986 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002987 printf(_("You haven't covered the whole disk with "
2988 "the 3rd partition, but your value\n"
2989 "%d %s covers some other partition. "
2990 "Your entry has been changed\n"
2991 "to %d %s\n"),
2992 scround(last), str_units(SINGULAR),
2993 scround(stop), str_units(SINGULAR));
2994 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002995 }
2996 } else if (!whole_disk && last > stop)
2997 last = stop;
2998
Rob Landleyb73451d2006-02-24 16:29:00 +00002999 if (whole_disk)
3000 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003001 set_sun_partition(n, first, last, sys);
3002}
3003
3004static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003005sun_delete_partition(int i)
3006{
Eric Andersen040f4402003-07-30 08:40:37 +00003007 unsigned int nsec;
3008
Rob Landleyb73451d2006-02-24 16:29:00 +00003009 if (i == 2
3010 && sunlabel->infos[i].id == WHOLE_DISK
3011 && !sunlabel->partitions[i].start_cylinder
3012 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003013 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003014 "consider leaving this\n"
3015 "partition as Whole disk (5), starting at 0, with %u "
3016 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003017 sunlabel->infos[i].id = 0;
3018 sunlabel->partitions[i].num_sectors = 0;
3019}
3020
3021static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003022sun_change_sysid(int i, int sys)
3023{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003024 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003025 read_chars(
3026 _("It is highly recommended that the partition at offset 0\n"
3027 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3028 "there may destroy your partition table and bootblock.\n"
3029 "Type YES if you're very sure you would like that partition\n"
3030 "tagged with 82 (Linux swap): "));
3031 if (strcmp (line_ptr, _("YES\n")))
3032 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003033 }
3034 switch (sys) {
3035 case SUNOS_SWAP:
3036 case LINUX_SWAP:
3037 /* swaps are not mountable by default */
3038 sunlabel->infos[i].flags |= 0x01;
3039 break;
3040 default:
3041 /* assume other types are mountable;
3042 user can change it anyway */
3043 sunlabel->infos[i].flags &= ~0x01;
3044 break;
3045 }
3046 sunlabel->infos[i].id = sys;
3047}
3048
3049static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003050sun_list_table(int xtra)
3051{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003052 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003053
3054 w = strlen(disk_device);
3055 if (xtra)
3056 printf(
3057 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3058 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3059 "%d extra sects/cyl, interleave %d:1\n"
3060 "%s\n"
3061 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003062 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3063 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3064 SUN_SSWAP16(sunlabel->pcylcount),
3065 SUN_SSWAP16(sunlabel->sparecyl),
3066 SUN_SSWAP16(sunlabel->ilfact),
3067 (char *)sunlabel,
3068 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003069 else
3070 printf(
3071 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3072 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003073 disk_device, heads, sectors, cylinders,
3074 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003075
3076 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003077 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003078 for (i = 0 ; i < partitions; i++) {
3079 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003080 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3081 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003082 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3083 partname(disk_device, i+1, w), /* device */
3084 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3085 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3086 (long) scround(start), /* start */
3087 (long) scround(start+len), /* end */
3088 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3089 sunlabel->infos[i].id, /* type id */
3090 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003091 }
3092 }
3093}
3094
Eric Andersen040f4402003-07-30 08:40:37 +00003095#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3096
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003097static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003098sun_set_alt_cyl(void)
3099{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003100 sunlabel->nacyl =
3101 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003102 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003103}
3104
3105static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003106sun_set_ncyl(int cyl)
3107{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003108 sunlabel->ncyl = SUN_SSWAP16(cyl);
3109}
3110
3111static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003112sun_set_xcyl(void)
3113{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003114 sunlabel->sparecyl =
3115 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003116 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003117}
3118
3119static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003120sun_set_ilfact(void)
3121{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003122 sunlabel->ilfact =
3123 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003124 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003125}
3126
3127static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003128sun_set_rspeed(void)
3129{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003130 sunlabel->rspeed =
3131 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003132 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003133}
3134
3135static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003136sun_set_pcylcount(void)
3137{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003138 sunlabel->pcylcount =
3139 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003140 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003141}
Eric Andersen040f4402003-07-30 08:40:37 +00003142#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003143
3144static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003145sun_write_table(void)
3146{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003147 unsigned short *ush = (unsigned short *)sunlabel;
3148 unsigned short csum = 0;
3149
Rob Landleyb73451d2006-02-24 16:29:00 +00003150 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003151 csum ^= *ush++;
3152 sunlabel->csum = csum;
3153 if (lseek(fd, 0, SEEK_SET) < 0)
3154 fdisk_fatal(unable_to_seek);
3155 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3156 fdisk_fatal(unable_to_write);
3157}
3158#endif /* SUN_LABEL */
3159
3160/* DOS partition types */
3161
3162static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003163 { "\x00" "Empty" },
3164 { "\x01" "FAT12" },
3165 { "\x04" "FAT16 <32M" },
3166 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3167 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3168 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3169 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3170 { "\x0b" "Win95 FAT32" },
3171 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3172 { "\x0e" "Win95 FAT16 (LBA)" },
3173 { "\x0f" "Win95 Ext'd (LBA)" },
3174 { "\x11" "Hidden FAT12" },
3175 { "\x12" "Compaq diagnostics" },
3176 { "\x14" "Hidden FAT16 <32M" },
3177 { "\x16" "Hidden FAT16" },
3178 { "\x17" "Hidden HPFS/NTFS" },
3179 { "\x1b" "Hidden Win95 FAT32" },
3180 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3181 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3182 { "\x3c" "PartitionMagic recovery" },
3183 { "\x41" "PPC PReP Boot" },
3184 { "\x42" "SFS" },
3185 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3186 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3187 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3188 { "\x82" "Linux swap" }, /* also Solaris */
3189 { "\x83" "Linux" },
3190 { "\x84" "OS/2 hidden C: drive" },
3191 { "\x85" "Linux extended" },
3192 { "\x86" "NTFS volume set" },
3193 { "\x87" "NTFS volume set" },
3194 { "\x8e" "Linux LVM" },
3195 { "\x9f" "BSD/OS" }, /* BSDI */
3196 { "\xa0" "IBM Thinkpad hibernation" },
3197 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3198 { "\xa6" "OpenBSD" },
3199 { "\xa8" "Darwin UFS" },
3200 { "\xa9" "NetBSD" },
3201 { "\xab" "Darwin boot" },
3202 { "\xb7" "BSDI fs" },
3203 { "\xb8" "BSDI swap" },
3204 { "\xbe" "Solaris boot" },
3205 { "\xeb" "BeOS fs" },
3206 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3207 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3208 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3209 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3210 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3211 autodetect using persistent
3212 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003213#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003214 { "\x02" "XENIX root" },
3215 { "\x03" "XENIX usr" },
3216 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3217 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3218 { "\x10" "OPUS" },
3219 { "\x18" "AST SmartSleep" },
3220 { "\x24" "NEC DOS" },
3221 { "\x39" "Plan 9" },
3222 { "\x40" "Venix 80286" },
3223 { "\x4d" "QNX4.x" },
3224 { "\x4e" "QNX4.x 2nd part" },
3225 { "\x4f" "QNX4.x 3rd part" },
3226 { "\x50" "OnTrack DM" },
3227 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3228 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3229 { "\x53" "OnTrack DM6 Aux3" },
3230 { "\x54" "OnTrackDM6" },
3231 { "\x55" "EZ-Drive" },
3232 { "\x56" "Golden Bow" },
3233 { "\x5c" "Priam Edisk" },
3234 { "\x61" "SpeedStor" },
3235 { "\x64" "Novell Netware 286" },
3236 { "\x65" "Novell Netware 386" },
3237 { "\x70" "DiskSecure Multi-Boot" },
3238 { "\x75" "PC/IX" },
3239 { "\x93" "Amoeba" },
3240 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3241 { "\xa7" "NeXTSTEP" },
3242 { "\xbb" "Boot Wizard hidden" },
3243 { "\xc1" "DRDOS/sec (FAT-12)" },
3244 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3245 { "\xc6" "DRDOS/sec (FAT-16)" },
3246 { "\xc7" "Syrinx" },
3247 { "\xda" "Non-FS data" },
3248 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003249 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003250 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3251 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3252 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003253 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003254 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3255 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003256 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003257 { "\xf1" "SpeedStor" },
3258 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3259 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3260 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003261#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003262 { 0 }
3263};
3264
3265
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003266
3267/* A valid partition table sector ends in 0x55 0xaa */
3268static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003269part_table_flag(const char *b)
3270{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003271 return ((uint) b[510]) + (((uint) b[511]) << 8);
3272}
3273
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003274
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003275#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003276static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003277write_part_table_flag(char *b)
3278{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003279 b[510] = 0x55;
3280 b[511] = 0xaa;
3281}
3282
3283/* start_sect and nr_sects are stored little endian on all machines */
3284/* moreover, they are not aligned correctly */
3285static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003286store4_little_endian(unsigned char *cp, unsigned int val)
3287{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003288 cp[0] = (val & 0xff);
3289 cp[1] = ((val >> 8) & 0xff);
3290 cp[2] = ((val >> 16) & 0xff);
3291 cp[3] = ((val >> 24) & 0xff);
3292}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003293#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003294
3295static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003296read4_little_endian(const unsigned char *cp)
3297{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003298 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3299 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3300}
3301
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003302#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003303static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003304set_start_sect(struct partition *p, unsigned int start_sect)
3305{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003306 store4_little_endian(p->start4, start_sect);
3307}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003308#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003309
Eric Andersend9261492004-06-28 23:50:31 +00003310static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003311get_start_sect(const struct partition *p)
3312{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003313 return read4_little_endian(p->start4);
3314}
3315
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003316#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003317static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003318set_nr_sects(struct partition *p, int32_t nr_sects)
3319{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003320 store4_little_endian(p->size4, nr_sects);
3321}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003322#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003323
Eric Andersend9261492004-06-28 23:50:31 +00003324static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003325get_nr_sects(const struct partition *p)
3326{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003327 return read4_little_endian(p->size4);
3328}
3329
3330/* normally O_RDWR, -l option gives O_RDONLY */
3331static int type_open = O_RDWR;
3332
3333
Rob Landleyb73451d2006-02-24 16:29:00 +00003334static int ext_index; /* the prime extended partition */
3335static int listing; /* no aborts for fdisk -l */
3336static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003337#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3338static int dos_changed;
3339static int nowarn; /* no warnings for fdisk -l/-s */
3340#endif
3341
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003342
3343
Rob Landleyb73451d2006-02-24 16:29:00 +00003344static uint user_cylinders, user_heads, user_sectors;
3345static uint pt_heads, pt_sectors;
3346static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003347
Eric Andersend9261492004-06-28 23:50:31 +00003348static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003349
Eric Andersen040f4402003-07-30 08:40:37 +00003350static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003351
3352
3353static jmp_buf listingbuf;
3354
Rob Landleyb73451d2006-02-24 16:29:00 +00003355static void fdisk_fatal(enum failure why)
3356{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003357 const char *message;
3358
3359 if (listing) {
3360 close(fd);
3361 longjmp(listingbuf, 1);
3362 }
3363
3364 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003365 case unable_to_open:
3366 message = "Unable to open %s\n";
3367 break;
3368 case unable_to_read:
3369 message = "Unable to read %s\n";
3370 break;
3371 case unable_to_seek:
3372 message = "Unable to seek on %s\n";
3373 break;
3374 case unable_to_write:
3375 message = "Unable to write %s\n";
3376 break;
3377 case ioctl_error:
3378 message = "BLKGETSIZE ioctl failed on %s\n";
3379 break;
3380 default:
3381 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003382 }
3383
3384 fputc('\n', stderr);
3385 fprintf(stderr, message, disk_device);
3386 exit(1);
3387}
3388
3389static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003390seek_sector(off_t secno)
3391{
Eric Andersen0a92f352004-03-30 09:21:54 +00003392 off_t offset = secno * sector_size;
3393 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003394 fdisk_fatal(unable_to_seek);
3395}
3396
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003397#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003398static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003399write_sector(off_t secno, char *buf)
3400{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003401 seek_sector(secno);
3402 if (write(fd, buf, sector_size) != sector_size)
3403 fdisk_fatal(unable_to_write);
3404}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003405#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003406
3407/* Allocate a buffer and read a partition table sector */
3408static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003409read_pte(struct pte *pe, off_t offset)
3410{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003411 pe->offset = offset;
3412 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003413 seek_sector(offset);
3414 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3415 fdisk_fatal(unable_to_read);
3416#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003417 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003418#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003419 pe->part_table = pe->ext_pointer = NULL;
3420}
3421
3422static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003423get_partition_start(const struct pte *pe)
3424{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003425 return pe->offset + get_start_sect(pe->part_table);
3426}
3427
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003428#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003429/*
3430 * Avoid warning about DOS partitions when no DOS partition was changed.
3431 * Here a heuristic "is probably dos partition".
3432 * We might also do the opposite and warn in all cases except
3433 * for "is probably nondos partition".
3434 */
3435static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003436is_dos_partition(int t)
3437{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003438 return (t == 1 || t == 4 || t == 6 ||
3439 t == 0x0b || t == 0x0c || t == 0x0e ||
3440 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3441 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3442 t == 0xc1 || t == 0xc4 || t == 0xc6);
3443}
3444
3445static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003446menu(void)
3447{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003448#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003449 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003450 puts(_("Command action"));
3451 puts(_("\ta\ttoggle a read only flag")); /* sun */
3452 puts(_("\tb\tedit bsd disklabel"));
3453 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3454 puts(_("\td\tdelete a partition"));
3455 puts(_("\tl\tlist known partition types"));
3456 puts(_("\tm\tprint this menu"));
3457 puts(_("\tn\tadd a new partition"));
3458 puts(_("\to\tcreate a new empty DOS partition table"));
3459 puts(_("\tp\tprint the partition table"));
3460 puts(_("\tq\tquit without saving changes"));
3461 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3462 puts(_("\tt\tchange a partition's system id"));
3463 puts(_("\tu\tchange display/entry units"));
3464 puts(_("\tv\tverify the partition table"));
3465 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003466#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003467 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003468#endif
3469 } else
3470#endif
3471#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003472 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003473 puts(_("Command action"));
3474 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3475 puts(_("\tb\tedit bootfile entry")); /* sgi */
3476 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3477 puts(_("\td\tdelete a partition"));
3478 puts(_("\tl\tlist known partition types"));
3479 puts(_("\tm\tprint this menu"));
3480 puts(_("\tn\tadd a new partition"));
3481 puts(_("\to\tcreate a new empty DOS partition table"));
3482 puts(_("\tp\tprint the partition table"));
3483 puts(_("\tq\tquit without saving changes"));
3484 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3485 puts(_("\tt\tchange a partition's system id"));
3486 puts(_("\tu\tchange display/entry units"));
3487 puts(_("\tv\tverify the partition table"));
3488 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003489 } else
3490#endif
3491#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003492 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003493 puts(_("Command action"));
3494 puts(_("\tm\tprint this menu"));
3495 puts(_("\to\tcreate a new empty DOS partition table"));
3496 puts(_("\tq\tquit without saving changes"));
3497 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003498 } else
3499#endif
3500 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003501 puts(_("Command action"));
3502 puts(_("\ta\ttoggle a bootable flag"));
3503 puts(_("\tb\tedit bsd disklabel"));
3504 puts(_("\tc\ttoggle the dos compatibility flag"));
3505 puts(_("\td\tdelete a partition"));
3506 puts(_("\tl\tlist known partition types"));
3507 puts(_("\tm\tprint this menu"));
3508 puts(_("\tn\tadd a new partition"));
3509 puts(_("\to\tcreate a new empty DOS partition table"));
3510 puts(_("\tp\tprint the partition table"));
3511 puts(_("\tq\tquit without saving changes"));
3512 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3513 puts(_("\tt\tchange a partition's system id"));
3514 puts(_("\tu\tchange display/entry units"));
3515 puts(_("\tv\tverify the partition table"));
3516 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003517#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003518 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003519#endif
3520 }
3521}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003522#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3523
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003524
3525#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3526static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003527xmenu(void)
3528{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003529#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003530 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003531 puts(_("Command action"));
3532 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3533 puts(_("\tc\tchange number of cylinders"));
3534 puts(_("\td\tprint the raw data in the partition table"));
3535 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3536 puts(_("\th\tchange number of heads"));
3537 puts(_("\ti\tchange interleave factor")); /*sun*/
3538 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3539 puts(_("\tm\tprint this menu"));
3540 puts(_("\tp\tprint the partition table"));
3541 puts(_("\tq\tquit without saving changes"));
3542 puts(_("\tr\treturn to main menu"));
3543 puts(_("\ts\tchange number of sectors/track"));
3544 puts(_("\tv\tverify the partition table"));
3545 puts(_("\tw\twrite table to disk and exit"));
3546 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003547 } else
3548#endif
3549#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003550 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003551 puts(_("Command action"));
3552 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3553 puts(_("\tc\tchange number of cylinders"));
3554 puts(_("\td\tprint the raw data in the partition table"));
3555 puts(_("\te\tlist extended partitions")); /* !sun */
3556 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3557 puts(_("\th\tchange number of heads"));
3558 puts(_("\tm\tprint this menu"));
3559 puts(_("\tp\tprint the partition table"));
3560 puts(_("\tq\tquit without saving changes"));
3561 puts(_("\tr\treturn to main menu"));
3562 puts(_("\ts\tchange number of sectors/track"));
3563 puts(_("\tv\tverify the partition table"));
3564 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003565 } else
3566#endif
3567#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003568 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003569 puts(_("Command action"));
3570 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3571 puts(_("\tc\tchange number of cylinders"));
3572 puts(_("\td\tprint the raw data in the partition table"));
3573 puts(_("\te\tlist extended partitions")); /* !sun */
3574 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3575 puts(_("\th\tchange number of heads"));
3576 puts(_("\tm\tprint this menu"));
3577 puts(_("\tp\tprint the partition table"));
3578 puts(_("\tq\tquit without saving changes"));
3579 puts(_("\tr\treturn to main menu"));
3580 puts(_("\ts\tchange number of sectors/track"));
3581 puts(_("\tv\tverify the partition table"));
3582 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003583 } else
3584#endif
3585 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003586 puts(_("Command action"));
3587 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3588 puts(_("\tc\tchange number of cylinders"));
3589 puts(_("\td\tprint the raw data in the partition table"));
3590 puts(_("\te\tlist extended partitions")); /* !sun */
3591 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003592#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003593 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003594#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003595 puts(_("\th\tchange number of heads"));
3596 puts(_("\tm\tprint this menu"));
3597 puts(_("\tp\tprint the partition table"));
3598 puts(_("\tq\tquit without saving changes"));
3599 puts(_("\tr\treturn to main menu"));
3600 puts(_("\ts\tchange number of sectors/track"));
3601 puts(_("\tv\tverify the partition table"));
3602 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003603 }
3604}
3605#endif /* ADVANCED mode */
3606
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003607#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003608static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003609get_sys_types(void)
3610{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003611 return (
3612#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003613 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003614#endif
3615#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003616 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003617#endif
3618 i386_sys_types);
3619}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003620#else
3621#define get_sys_types() i386_sys_types
3622#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003623
3624static const char *partition_type(unsigned char type)
3625{
3626 int i;
3627 const struct systypes *types = get_sys_types();
3628
Rob Landleyb73451d2006-02-24 16:29:00 +00003629 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003630 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003631 return types[i].name + 1;
3632
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003633 return _("Unknown");
3634}
3635
3636
3637#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3638static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003639get_sysid(int i)
3640{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003641 return (
3642#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003643 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003644#endif
3645#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003646 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003647#endif
3648 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003649}
3650
3651void list_types(const struct systypes *sys)
3652{
3653 uint last[4], done = 0, next = 0, size;
3654 int i;
3655
3656 for (i = 0; sys[i].name; i++);
3657 size = i;
3658
3659 for (i = 3; i >= 0; i--)
3660 last[3 - i] = done += (size + i - done) / (i + 1);
3661 i = done = 0;
3662
3663 do {
3664 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003665 (unsigned char)sys[next].name[0],
3666 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003667 next = last[i++] + done;
3668 if (i > 3 || next >= last[i]) {
3669 i = 0;
3670 next = ++done;
3671 }
3672 } while (done < last[0]);
3673 putchar('\n');
3674}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003675#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003676
3677static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003678is_cleared_partition(const struct partition *p)
3679{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003680 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3681 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3682 get_start_sect(p) || get_nr_sects(p));
3683}
3684
3685static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003686clear_partition(struct partition *p)
3687{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003688 if (!p)
3689 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003690 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003691}
3692
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003693#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003694static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003695set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3696{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003697 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003698 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003699
3700 if (doext) {
3701 p = ptes[i].ext_pointer;
3702 offset = extended_offset;
3703 } else {
3704 p = ptes[i].part_table;
3705 offset = ptes[i].offset;
3706 }
3707 p->boot_ind = 0;
3708 p->sys_ind = sysid;
3709 set_start_sect(p, start - offset);
3710 set_nr_sects(p, stop - start + 1);
3711 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3712 start = heads*sectors*1024 - 1;
3713 set_hsc(p->head, p->sector, p->cyl, start);
3714 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3715 stop = heads*sectors*1024 - 1;
3716 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3717 ptes[i].changed = 1;
3718}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003719#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003720
3721static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003722test_c(const char **m, const char *mesg)
3723{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003724 int val = 0;
3725 if (!*m)
3726 fprintf(stderr, _("You must set"));
3727 else {
3728 fprintf(stderr, " %s", *m);
3729 val = 1;
3730 }
3731 *m = mesg;
3732 return val;
3733}
3734
3735static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003736warn_geometry(void)
3737{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003738 const char *m = NULL;
3739 int prev = 0;
3740
3741 if (!heads)
3742 prev = test_c(&m, _("heads"));
3743 if (!sectors)
3744 prev = test_c(&m, _("sectors"));
3745 if (!cylinders)
3746 prev = test_c(&m, _("cylinders"));
3747 if (!m)
3748 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003749
3750 fprintf(stderr, "%s%s.\n"
3751#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3752 "You can do this from the extra functions menu.\n"
3753#endif
3754 , prev ? _(" and ") : " ", m);
3755
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003756 return 1;
3757}
3758
3759static void update_units(void)
3760{
3761 int cyl_units = heads * sectors;
3762
3763 if (display_in_cyl_units && cyl_units)
3764 units_per_sector = cyl_units;
3765 else
3766 units_per_sector = 1; /* in sectors */
3767}
3768
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003769#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003770static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003771warn_cylinders(void)
3772{
Rob Landley5527b912006-02-25 03:46:10 +00003773 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003774 fprintf(stderr, _("\n"
3775"The number of cylinders for this disk is set to %d.\n"
3776"There is nothing wrong with that, but this is larger than 1024,\n"
3777"and could in certain setups cause problems with:\n"
3778"1) software that runs at boot time (e.g., old versions of LILO)\n"
3779"2) booting and partitioning software from other OSs\n"
3780" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3781 cylinders);
3782}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003783#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003784
3785static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003786read_extended(int ext)
3787{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003788 int i;
3789 struct pte *pex;
3790 struct partition *p, *q;
3791
3792 ext_index = ext;
3793 pex = &ptes[ext];
3794 pex->ext_pointer = pex->part_table;
3795
3796 p = pex->part_table;
3797 if (!get_start_sect(p)) {
3798 fprintf(stderr,
3799 _("Bad offset in primary extended partition\n"));
3800 return;
3801 }
3802
Rob Landleyb73451d2006-02-24 16:29:00 +00003803 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003804 struct pte *pe = &ptes[partitions];
3805
3806 if (partitions >= MAXIMUM_PARTS) {
3807 /* This is not a Linux restriction, but
3808 this program uses arrays of size MAXIMUM_PARTS.
3809 Do not try to `improve' this test. */
3810 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003811#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003812 fprintf(stderr,
3813 _("Warning: deleting partitions after %d\n"),
3814 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003815 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003816#endif
3817 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003818 return;
3819 }
3820
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003821 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003822
3823 if (!extended_offset)
3824 extended_offset = get_start_sect(p);
3825
3826 q = p = pt_offset(pe->sectorbuffer, 0);
3827 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003828 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003829 if (pe->ext_pointer)
3830 fprintf(stderr,
3831 _("Warning: extra link "
3832 "pointer in partition table"
3833 " %d\n"), partitions + 1);
3834 else
3835 pe->ext_pointer = p;
3836 } else if (p->sys_ind) {
3837 if (pe->part_table)
3838 fprintf(stderr,
3839 _("Warning: ignoring extra "
3840 "data in partition table"
3841 " %d\n"), partitions + 1);
3842 else
3843 pe->part_table = p;
3844 }
3845 }
3846
3847 /* very strange code here... */
3848 if (!pe->part_table) {
3849 if (q != pe->ext_pointer)
3850 pe->part_table = q;
3851 else
3852 pe->part_table = q + 1;
3853 }
3854 if (!pe->ext_pointer) {
3855 if (q != pe->part_table)
3856 pe->ext_pointer = q;
3857 else
3858 pe->ext_pointer = q + 1;
3859 }
3860
3861 p = pe->ext_pointer;
3862 partitions++;
3863 }
3864
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003865#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003866 /* remove empty links */
3867 remove:
3868 for (i = 4; i < partitions; i++) {
3869 struct pte *pe = &ptes[i];
3870
3871 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003872 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003873 printf("omitting empty partition (%d)\n", i+1);
3874 delete_partition(i);
3875 goto remove; /* numbering changed */
3876 }
3877 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003878#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003879}
3880
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003881#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003882static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003883create_doslabel(void)
3884{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003885 int i;
3886
3887 fprintf(stderr,
3888 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3889 "until you decide to write them. After that, of course, the previous\n"
3890 "content won't be recoverable.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00003891
3892 current_label_type = label_dos;
3893
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003894#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003895 possibly_osf_label = 0;
3896#endif
3897 partitions = 4;
3898
3899 for (i = 510-64; i < 510; i++)
3900 MBRbuffer[i] = 0;
3901 write_part_table_flag(MBRbuffer);
3902 extended_offset = 0;
3903 set_all_unchanged();
3904 set_changed(0);
3905 get_boot(create_empty_dos);
3906}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003907#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003908
3909static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003910get_sectorsize(void)
3911{
Rob Landley736e5252006-02-25 03:36:00 +00003912 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003913 int arg;
3914 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3915 sector_size = arg;
3916 if (sector_size != DEFAULT_SECTOR_SIZE)
3917 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003918 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003919 }
3920}
3921
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003922static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003923get_kernel_geometry(void)
3924{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003925 struct hd_geometry geometry;
3926
3927 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3928 kern_heads = geometry.heads;
3929 kern_sectors = geometry.sectors;
3930 /* never use geometry.cylinders - it is truncated */
3931 }
3932}
3933
3934static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003935get_partition_table_geometry(void)
3936{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003937 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003938 struct partition *p;
3939 int i, h, s, hh, ss;
3940 int first = 1;
3941 int bad = 0;
3942
Eric Andersen3496fdc2006-01-30 23:09:20 +00003943 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003944 return;
3945
3946 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003947 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003948 p = pt_offset(bufp, i);
3949 if (p->sys_ind != 0) {
3950 h = p->end_head + 1;
3951 s = (p->end_sector & 077);
3952 if (first) {
3953 hh = h;
3954 ss = s;
3955 first = 0;
3956 } else if (hh != h || ss != s)
3957 bad = 1;
3958 }
3959 }
3960
3961 if (!first && !bad) {
3962 pt_heads = hh;
3963 pt_sectors = ss;
3964 }
3965}
3966
Rob Landleyb73451d2006-02-24 16:29:00 +00003967static void
3968get_geometry(void)
3969{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003970 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003971 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003972
3973 get_sectorsize();
3974 sec_fac = sector_size / 512;
3975#ifdef CONFIG_FEATURE_SUN_LABEL
3976 guess_device_type();
3977#endif
3978 heads = cylinders = sectors = 0;
3979 kern_heads = kern_sectors = 0;
3980 pt_heads = pt_sectors = 0;
3981
3982 get_kernel_geometry();
3983 get_partition_table_geometry();
3984
3985 heads = user_heads ? user_heads :
3986 pt_heads ? pt_heads :
3987 kern_heads ? kern_heads : 255;
3988 sectors = user_sectors ? user_sectors :
3989 pt_sectors ? pt_sectors :
3990 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003991 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3992 /* got bytes */
3993 } else {
3994 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003995
3996 if (ioctl(fd, BLKGETSIZE, &longsectors))
3997 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00003998 bytes = ((unsigned long long) longsectors) << 9;
3999 }
4000
4001 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004002
4003 sector_offset = 1;
4004 if (dos_compatible_flag)
4005 sector_offset = sectors;
4006
Eric Andersen040f4402003-07-30 08:40:37 +00004007 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004008 if (!cylinders)
4009 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004010}
4011
4012/*
4013 * Read MBR. Returns:
4014 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4015 * 0: found or created label
4016 * 1: I/O error
4017 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004018static int
4019get_boot(enum action what)
4020{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004021 int i;
4022
4023 partitions = 4;
4024
4025 for (i = 0; i < 4; i++) {
4026 struct pte *pe = &ptes[i];
4027
4028 pe->part_table = pt_offset(MBRbuffer, i);
4029 pe->ext_pointer = NULL;
4030 pe->offset = 0;
4031 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004032#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004033 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004034#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004035 }
4036
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004037#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004038 if (what == create_empty_sun && check_sun_label())
4039 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004040#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004041
4042 memset(MBRbuffer, 0, 512);
4043
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004044#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004045 if (what == create_empty_dos)
4046 goto got_dos_table; /* skip reading disk */
4047
4048 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004049 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4050 if (what == try_only)
4051 return 1;
4052 fdisk_fatal(unable_to_open);
4053 } else
4054 printf(_("You will not be able to write "
4055 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004056 }
4057
4058 if (512 != read(fd, MBRbuffer, 512)) {
4059 if (what == try_only)
4060 return 1;
4061 fdisk_fatal(unable_to_read);
4062 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004063#else
4064 if ((fd = open(disk_device, O_RDONLY)) < 0)
4065 return 1;
4066 if (512 != read(fd, MBRbuffer, 512))
4067 return 1;
4068#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004069
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004070 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004071
4072 update_units();
4073
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004074#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004075 if (check_sun_label())
4076 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004077#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004078
4079#ifdef CONFIG_FEATURE_SGI_LABEL
4080 if (check_sgi_label())
4081 return 0;
4082#endif
4083
4084#ifdef CONFIG_FEATURE_AIX_LABEL
4085 if (check_aix_label())
4086 return 0;
4087#endif
4088
4089#ifdef CONFIG_FEATURE_OSF_LABEL
4090 if (check_osf_label()) {
4091 possibly_osf_label = 1;
4092 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004093 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004094 return 0;
4095 }
4096 printf(_("This disk has both DOS and BSD magic.\n"
4097 "Give the 'b' command to go to BSD mode.\n"));
4098 }
4099#endif
4100
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004101#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004102 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004103#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004104
4105 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004106#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4107 return -1;
4108#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004109 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004110 case fdisk:
4111 fprintf(stderr,
4112 _("Device contains neither a valid DOS "
4113 "partition table, nor Sun, SGI or OSF "
4114 "disklabel\n"));
4115#ifdef __sparc__
4116#ifdef CONFIG_FEATURE_SUN_LABEL
4117 create_sunlabel();
4118#endif
4119#else
4120 create_doslabel();
4121#endif
4122 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004123 case try_only:
4124 return -1;
4125 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004126#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004127 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004128#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004129 break;
4130 default:
4131 fprintf(stderr, _("Internal error\n"));
4132 exit(1);
4133 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004134#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004135 }
4136
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004137#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004138 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004139#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004140 warn_geometry();
4141
4142 for (i = 0; i < 4; i++) {
4143 struct pte *pe = &ptes[i];
4144
Rob Landleyb73451d2006-02-24 16:29:00 +00004145 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004146 if (partitions != 4)
4147 fprintf(stderr, _("Ignoring extra extended "
4148 "partition %d\n"), i + 1);
4149 else
4150 read_extended(i);
4151 }
4152 }
4153
4154 for (i = 3; i < partitions; i++) {
4155 struct pte *pe = &ptes[i];
4156
4157 if (!valid_part_table_flag(pe->sectorbuffer)) {
4158 fprintf(stderr,
4159 _("Warning: invalid flag 0x%04x of partition "
4160 "table %d will be corrected by w(rite)\n"),
4161 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004162#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004163 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004164#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004165 }
4166 }
4167
4168 return 0;
4169}
4170
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004171#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004172/*
4173 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4174 * If the user hits Enter, DFLT is returned.
4175 * Answers like +10 are interpreted as offsets from BASE.
4176 *
4177 * There is no default if DFLT is not between LOW and HIGH.
4178 */
4179static uint
4180read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4181{
4182 uint i;
4183 int default_ok = 1;
4184 static char *ms = NULL;
4185 static int mslen = 0;
4186
4187 if (!ms || strlen(mesg)+100 > mslen) {
4188 mslen = strlen(mesg)+200;
4189 ms = xrealloc(ms,mslen);
4190 }
4191
4192 if (dflt < low || dflt > high)
4193 default_ok = 0;
4194
4195 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004196 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004197 mesg, low, high, dflt);
4198 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004199 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004200
4201 while (1) {
4202 int use_default = default_ok;
4203
4204 /* ask question and read answer */
4205 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004206 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004207 continue;
4208
Eric Andersen84bdea82004-05-19 10:49:17 +00004209 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004210 int minus = (*line_ptr == '-');
4211 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004212
Rob Landleyb73451d2006-02-24 16:29:00 +00004213 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004214
Rob Landleyb73451d2006-02-24 16:29:00 +00004215 while (isdigit(*++line_ptr))
4216 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004217
Rob Landleyb73451d2006-02-24 16:29:00 +00004218 switch (*line_ptr) {
4219 case 'c':
4220 case 'C':
4221 if (!display_in_cyl_units)
4222 i *= heads * sectors;
4223 break;
4224 case 'K':
4225 absolute = 1024;
4226 break;
4227 case 'k':
4228 absolute = 1000;
4229 break;
4230 case 'm':
4231 case 'M':
4232 absolute = 1000000;
4233 break;
4234 case 'g':
4235 case 'G':
4236 absolute = 1000000000;
4237 break;
4238 default:
4239 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004240 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004241 if (absolute) {
4242 unsigned long long bytes;
4243 unsigned long unit;
4244
4245 bytes = (unsigned long long) i * absolute;
4246 unit = sector_size * units_per_sector;
4247 bytes += unit/2; /* round */
4248 bytes /= unit;
4249 i = bytes;
4250 }
4251 if (minus)
4252 i = -i;
4253 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004254 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004255 i = atoi(line_ptr);
4256 while (isdigit(*line_ptr)) {
4257 line_ptr++;
4258 use_default = 0;
4259 }
4260 }
4261 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004262 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004263 if (i >= low && i <= high)
4264 break;
4265 else
4266 printf(_("Value out of range.\n"));
4267 }
4268 return i;
4269}
4270
Rob Landleyb73451d2006-02-24 16:29:00 +00004271static int
4272get_partition(int warn, int max)
4273{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004274 struct pte *pe;
4275 int i;
4276
4277 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4278 pe = &ptes[i];
4279
4280 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004281 if (
4282 (
4283 label_sun != current_label_type &&
4284 label_sgi != current_label_type &&
4285 !pe->part_table->sys_ind
4286 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004287#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004288 || (
4289 label_sun == current_label_type &&
4290 (
4291 !sunlabel->partitions[i].num_sectors
4292 || !sunlabel->infos[i].id
4293 )
4294 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004295#endif
4296#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004297 || (
4298 label_sgi == current_label_type &&
4299 !sgi_get_num_sectors(i)
4300 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004301#endif
Rob Landley5527b912006-02-25 03:46:10 +00004302 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004303 fprintf(stderr,
4304 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004305 i+1
4306 );
4307 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004308 }
4309 return i;
4310}
4311
4312static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004313get_existing_partition(int warn, int max)
4314{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004315 int pno = -1;
4316 int i;
4317
4318 for (i = 0; i < max; i++) {
4319 struct pte *pe = &ptes[i];
4320 struct partition *p = pe->part_table;
4321
4322 if (p && !is_cleared_partition(p)) {
4323 if (pno >= 0)
4324 goto not_unique;
4325 pno = i;
4326 }
4327 }
4328 if (pno >= 0) {
4329 printf(_("Selected partition %d\n"), pno+1);
4330 return pno;
4331 }
4332 printf(_("No partition is defined yet!\n"));
4333 return -1;
4334
4335 not_unique:
4336 return get_partition(warn, max);
4337}
4338
4339static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004340get_nonexisting_partition(int warn, int max)
4341{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004342 int pno = -1;
4343 int i;
4344
4345 for (i = 0; i < max; i++) {
4346 struct pte *pe = &ptes[i];
4347 struct partition *p = pe->part_table;
4348
4349 if (p && is_cleared_partition(p)) {
4350 if (pno >= 0)
4351 goto not_unique;
4352 pno = i;
4353 }
4354 }
4355 if (pno >= 0) {
4356 printf(_("Selected partition %d\n"), pno+1);
4357 return pno;
4358 }
4359 printf(_("All primary partitions have been defined already!\n"));
4360 return -1;
4361
4362 not_unique:
4363 return get_partition(warn, max);
4364}
4365
4366
4367void change_units(void)
4368{
4369 display_in_cyl_units = !display_in_cyl_units;
4370 update_units();
4371 printf(_("Changing display/entry units to %s\n"),
4372 str_units(PLURAL));
4373}
4374
4375static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004376toggle_active(int i)
4377{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004378 struct pte *pe = &ptes[i];
4379 struct partition *p = pe->part_table;
4380
Rob Landleyb73451d2006-02-24 16:29:00 +00004381 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004382 fprintf(stderr,
4383 _("WARNING: Partition %d is an extended partition\n"),
4384 i + 1);
4385 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4386 pe->changed = 1;
4387}
4388
4389static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004390toggle_dos_compatibility_flag(void)
4391{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004392 dos_compatible_flag = ~dos_compatible_flag;
4393 if (dos_compatible_flag) {
4394 sector_offset = sectors;
4395 printf(_("DOS Compatibility flag is set\n"));
4396 }
4397 else {
4398 sector_offset = 1;
4399 printf(_("DOS Compatibility flag is not set\n"));
4400 }
4401}
4402
4403static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004404delete_partition(int i)
4405{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004406 struct pte *pe = &ptes[i];
4407 struct partition *p = pe->part_table;
4408 struct partition *q = pe->ext_pointer;
4409
4410/* Note that for the fifth partition (i == 4) we don't actually
4411 * decrement partitions.
4412 */
4413
4414 if (warn_geometry())
4415 return; /* C/H/S not set */
4416 pe->changed = 1;
4417
4418#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004419 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004420 sun_delete_partition(i);
4421 return;
4422 }
4423#endif
4424#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004425 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004426 sgi_delete_partition(i);
4427 return;
4428 }
4429#endif
4430
4431 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004432 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004433 partitions = 4;
4434 ptes[ext_index].ext_pointer = NULL;
4435 extended_offset = 0;
4436 }
4437 clear_partition(p);
4438 return;
4439 }
4440
4441 if (!q->sys_ind && i > 4) {
4442 /* the last one in the chain - just delete */
4443 --partitions;
4444 --i;
4445 clear_partition(ptes[i].ext_pointer);
4446 ptes[i].changed = 1;
4447 } else {
4448 /* not the last one - further ones will be moved down */
4449 if (i > 4) {
4450 /* delete this link in the chain */
4451 p = ptes[i-1].ext_pointer;
4452 *p = *q;
4453 set_start_sect(p, get_start_sect(q));
4454 set_nr_sects(p, get_nr_sects(q));
4455 ptes[i-1].changed = 1;
4456 } else if (partitions > 5) { /* 5 will be moved to 4 */
4457 /* the first logical in a longer chain */
4458 pe = &ptes[5];
4459
4460 if (pe->part_table) /* prevent SEGFAULT */
4461 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004462 get_partition_start(pe) -
4463 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004464 pe->offset = extended_offset;
4465 pe->changed = 1;
4466 }
4467
4468 if (partitions > 5) {
4469 partitions--;
4470 while (i < partitions) {
4471 ptes[i] = ptes[i+1];
4472 i++;
4473 }
4474 } else
4475 /* the only logical: clear only */
4476 clear_partition(ptes[i].part_table);
4477 }
4478}
4479
4480static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004481change_sysid(void)
4482{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004483 int i, sys, origsys;
4484 struct partition *p;
4485
Eric Andersen040f4402003-07-30 08:40:37 +00004486#ifdef CONFIG_FEATURE_SGI_LABEL
4487 /* If sgi_label then don't use get_existing_partition,
4488 let the user select a partition, since get_existing_partition()
4489 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004490 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004491 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004492 } else {
4493 i = get_partition(0, partitions);
4494 }
4495#else
4496 i = get_existing_partition(0, partitions);
4497#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004498 if (i == -1)
4499 return;
4500 p = ptes[i].part_table;
4501 origsys = sys = get_sysid(i);
4502
4503 /* if changing types T to 0 is allowed, then
4504 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004505 if (!sys && label_sgi != current_label_type &&
4506 label_sun != current_label_type && !get_nr_sects(p))
4507 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004508 printf(_("Partition %d does not exist yet!\n"), i + 1);
Rob Landley5527b912006-02-25 03:46:10 +00004509 }else{
4510 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004511 sys = read_hex (get_sys_types());
4512
Rob Landley5527b912006-02-25 03:46:10 +00004513 if (!sys && label_sgi != current_label_type &&
4514 label_sun != current_label_type)
4515 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004516 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004517 "(but not to Linux). Having partitions of\n"
4518 "type 0 is probably unwise. You can delete\n"
4519 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004520 /* break; */
4521 }
4522
Rob Landley5527b912006-02-25 03:46:10 +00004523 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004524 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004525 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004526 " an extended one or vice versa\n"
4527 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004528 break;
4529 }
4530 }
4531
4532 if (sys < 256) {
4533#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004534 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004535 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004536 "as Whole disk (5),\n"
4537 "as SunOS/Solaris expects it and "
4538 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004539#endif
4540#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004541 if (label_sgi == current_label_type &&
4542 (
4543 (i == 10 && sys != ENTIRE_DISK) ||
4544 (i == 8 && sys != 0)
4545 )
4546 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004547 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004548 "as volume header (0),\nand "
4549 "partition 11 as entire volume (6)"
4550 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004551 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004552#endif
4553 if (sys == origsys)
4554 break;
4555#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004556 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004557 sun_change_sysid(i, sys);
4558 } else
4559#endif
4560#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004561 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004562 sgi_change_sysid(i, sys);
4563 } else
4564#endif
4565 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004566
Rob Landleyb73451d2006-02-24 16:29:00 +00004567 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004568 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004569 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004570 ptes[i].changed = 1;
4571 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004572 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004573 dos_changed = 1;
4574 break;
4575 }
Rob Landley5527b912006-02-25 03:46:10 +00004576 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004577 }
4578}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004579#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4580
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004581
4582/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4583 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4584 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4585 * Lubkin Oct. 1991). */
4586
Rob Landleyb73451d2006-02-24 16:29:00 +00004587static void
4588long2chs(ulong ls, uint *c, uint *h, uint *s)
4589{
4590 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004591
4592 *c = ls / spc;
4593 ls = ls % spc;
4594 *h = ls / sectors;
4595 *s = ls % sectors + 1; /* sectors count from 1 */
4596}
4597
Rob Landleyb73451d2006-02-24 16:29:00 +00004598static void
4599check_consistency(const struct partition *p, int partition)
4600{
4601 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4602 uint pec, peh, pes; /* physical ending c, h, s */
4603 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4604 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004605
4606 if (!heads || !sectors || (partition >= 4))
4607 return; /* do not check extended partitions */
4608
4609/* physical beginning c, h, s */
4610 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4611 pbh = p->head;
4612 pbs = p->sector & 0x3f;
4613
4614/* physical ending c, h, s */
4615 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4616 peh = p->end_head;
4617 pes = p->end_sector & 0x3f;
4618
4619/* compute logical beginning (c, h, s) */
4620 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4621
4622/* compute logical ending (c, h, s) */
4623 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4624
4625/* Same physical / logical beginning? */
4626 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4627 printf(_("Partition %d has different physical/logical "
4628 "beginnings (non-Linux?):\n"), partition + 1);
4629 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4630 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4631 }
4632
4633/* Same physical / logical ending? */
4634 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4635 printf(_("Partition %d has different physical/logical "
4636 "endings:\n"), partition + 1);
4637 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4638 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4639 }
4640
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004641/* Ending on cylinder boundary? */
4642 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004643 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004644 partition + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004645 }
4646}
4647
4648static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004649list_disk_geometry(void)
4650{
Eric Andersen040f4402003-07-30 08:40:37 +00004651 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004652 long megabytes = bytes/1000000;
4653
4654 if (megabytes < 10000)
4655 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004656 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004657 else
4658 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004659 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004660 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004661 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004662 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004663 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004664 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004665 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004666 str_units(PLURAL),
4667 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004668}
4669
4670/*
4671 * Check whether partition entries are ordered by their starting positions.
4672 * Return 0 if OK. Return i if partition i should have been earlier.
4673 * Two separate checks: primary and logical partitions.
4674 */
4675static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004676wrong_p_order(int *prev)
4677{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004678 const struct pte *pe;
4679 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004680 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004681 int i, last_i = 0;
4682
4683 for (i = 0 ; i < partitions; i++) {
4684 if (i == 4) {
4685 last_i = 4;
4686 last_p_start_pos = 0;
4687 }
4688 pe = &ptes[i];
4689 if ((p = pe->part_table)->sys_ind) {
4690 p_start_pos = get_partition_start(pe);
4691
4692 if (last_p_start_pos > p_start_pos) {
4693 if (prev)
4694 *prev = last_i;
4695 return i;
4696 }
4697
4698 last_p_start_pos = p_start_pos;
4699 last_i = i;
4700 }
4701 }
4702 return 0;
4703}
4704
4705#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4706/*
4707 * Fix the chain of logicals.
4708 * extended_offset is unchanged, the set of sectors used is unchanged
4709 * The chain is sorted so that sectors increase, and so that
4710 * starting sectors increase.
4711 *
4712 * After this it may still be that cfdisk doesnt like the table.
4713 * (This is because cfdisk considers expanded parts, from link to
4714 * end of partition, and these may still overlap.)
4715 * Now
4716 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4717 * may help.
4718 */
4719static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004720fix_chain_of_logicals(void)
4721{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004722 int j, oj, ojj, sj, sjj;
4723 struct partition *pj,*pjj,tmp;
4724
4725 /* Stage 1: sort sectors but leave sector of part 4 */
4726 /* (Its sector is the global extended_offset.) */
4727 stage1:
4728 for (j = 5; j < partitions-1; j++) {
4729 oj = ptes[j].offset;
4730 ojj = ptes[j+1].offset;
4731 if (oj > ojj) {
4732 ptes[j].offset = ojj;
4733 ptes[j+1].offset = oj;
4734 pj = ptes[j].part_table;
4735 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4736 pjj = ptes[j+1].part_table;
4737 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4738 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004739 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004740 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004741 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004742 goto stage1;
4743 }
4744 }
4745
4746 /* Stage 2: sort starting sectors */
4747 stage2:
4748 for (j = 4; j < partitions-1; j++) {
4749 pj = ptes[j].part_table;
4750 pjj = ptes[j+1].part_table;
4751 sj = get_start_sect(pj);
4752 sjj = get_start_sect(pjj);
4753 oj = ptes[j].offset;
4754 ojj = ptes[j+1].offset;
4755 if (oj+sj > ojj+sjj) {
4756 tmp = *pj;
4757 *pj = *pjj;
4758 *pjj = tmp;
4759 set_start_sect(pj, ojj+sjj-oj);
4760 set_start_sect(pjj, oj+sj-ojj);
4761 goto stage2;
4762 }
4763 }
4764
4765 /* Probably something was changed */
4766 for (j = 4; j < partitions; j++)
4767 ptes[j].changed = 1;
4768}
4769
4770
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004771static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004772fix_partition_table_order(void)
4773{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004774 struct pte *pei, *pek;
4775 int i,k;
4776
4777 if (!wrong_p_order(NULL)) {
4778 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4779 return;
4780 }
4781
4782 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4783 /* partition i should have come earlier, move it */
4784 /* We have to move data in the MBR */
4785 struct partition *pi, *pk, *pe, pbuf;
4786 pei = &ptes[i];
4787 pek = &ptes[k];
4788
4789 pe = pei->ext_pointer;
4790 pei->ext_pointer = pek->ext_pointer;
4791 pek->ext_pointer = pe;
4792
4793 pi = pei->part_table;
4794 pk = pek->part_table;
4795
4796 memmove(&pbuf, pi, sizeof(struct partition));
4797 memmove(pi, pk, sizeof(struct partition));
4798 memmove(pk, &pbuf, sizeof(struct partition));
4799
4800 pei->changed = pek->changed = 1;
4801 }
4802
4803 if (i)
4804 fix_chain_of_logicals();
4805
4806 printf("Done.\n");
4807
4808}
4809#endif
4810
4811static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004812list_table(int xtra)
4813{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004814 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004815 int i, w;
4816
4817#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004818 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004819 sun_list_table(xtra);
4820 return;
4821 }
4822#endif
4823
4824#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004825 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004826 sgi_list_table(xtra);
4827 return;
4828 }
4829#endif
4830
4831 list_disk_geometry();
4832
4833#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004834 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004835 xbsd_print_disklabel(xtra);
4836 return;
4837 }
4838#endif
4839
4840 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4841 but if the device name ends in a digit, say /dev/foo1,
4842 then the partition is called /dev/foo1p3. */
4843 w = strlen(disk_device);
4844 if (w && isdigit(disk_device[w-1]))
4845 w++;
4846 if (w < 5)
4847 w = 5;
4848
4849 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004850 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004851
4852 for (i = 0; i < partitions; i++) {
4853 const struct pte *pe = &ptes[i];
4854
4855 p = pe->part_table;
4856 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004857 off_t psects = get_nr_sects(p);
4858 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004859 unsigned int podd = 0;
4860
4861 if (sector_size < 1024) {
4862 pblocks /= (1024 / sector_size);
4863 podd = psects % (1024 / sector_size);
4864 }
4865 if (sector_size > 1024)
4866 pblocks *= (sector_size / 1024);
4867 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004868 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004869 partname(disk_device, i+1, w+2),
4870/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4871 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004872/* start */ (unsigned long long) cround(get_partition_start(pe)),
4873/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004874 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004875/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004876/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004877/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004878 check_consistency(p, i);
4879 }
4880 }
4881
4882 /* Is partition table in disk order? It need not be, but... */
4883 /* partition table entries are not checked for correct order if this
4884 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004885 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4886 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004887 printf(_("\nPartition table entries are not in disk order\n"));
4888 }
4889}
4890
4891#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4892static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004893x_list_table(int extend)
4894{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004895 const struct pte *pe;
4896 const struct partition *p;
4897 int i;
4898
4899 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4900 disk_device, heads, sectors, cylinders);
4901 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4902 for (i = 0 ; i < partitions; i++) {
4903 pe = &ptes[i];
4904 p = (extend ? pe->ext_pointer : pe->part_table);
4905 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004906 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004907 i + 1, p->boot_ind, p->head,
4908 sector(p->sector),
4909 cylinder(p->sector, p->cyl), p->end_head,
4910 sector(p->end_sector),
4911 cylinder(p->end_sector, p->end_cyl),
4912 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4913 if (p->sys_ind)
4914 check_consistency(p, i);
4915 }
4916 }
4917}
4918#endif
4919
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004920#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004921static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004922fill_bounds(off_t *first, off_t *last)
4923{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004924 int i;
4925 const struct pte *pe = &ptes[0];
4926 const struct partition *p;
4927
4928 for (i = 0; i < partitions; pe++,i++) {
4929 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004930 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004931 first[i] = 0xffffffff;
4932 last[i] = 0;
4933 } else {
4934 first[i] = get_partition_start(pe);
4935 last[i] = first[i] + get_nr_sects(p) - 1;
4936 }
4937 }
4938}
4939
4940static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004941check(int n, uint h, uint s, uint c, off_t start)
4942{
Eric Andersend9261492004-06-28 23:50:31 +00004943 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004944
4945 real_s = sector(s) - 1;
4946 real_c = cylinder(s, c);
4947 total = (real_c * sectors + real_s) * heads + h;
4948 if (!total)
4949 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4950 if (h >= heads)
4951 fprintf(stderr,
4952 _("Partition %d: head %d greater than maximum %d\n"),
4953 n, h + 1, heads);
4954 if (real_s >= sectors)
4955 fprintf(stderr, _("Partition %d: sector %d greater than "
4956 "maximum %d\n"), n, s, sectors);
4957 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004958 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4959 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004960 if (cylinders <= 1024 && start != total)
4961 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004962 _("Partition %d: previous sectors %llu disagrees with "
4963 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004964}
4965
4966static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004967verify(void)
4968{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004969 int i, j;
4970 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00004971 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004972 struct partition *p;
4973
4974 if (warn_geometry())
4975 return;
4976
4977#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004978 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004979 verify_sun();
4980 return;
4981 }
4982#endif
4983#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004984 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004985 verify_sgi(1);
4986 return;
4987 }
4988#endif
4989
4990 fill_bounds(first, last);
4991 for (i = 0; i < partitions; i++) {
4992 struct pte *pe = &ptes[i];
4993
4994 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004995 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004996 check_consistency(p, i);
4997 if (get_partition_start(pe) < first[i])
4998 printf(_("Warning: bad start-of-data in "
4999 "partition %d\n"), i + 1);
5000 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5001 last[i]);
5002 total += last[i] + 1 - first[i];
5003 for (j = 0; j < i; j++)
5004 if ((first[i] >= first[j] && first[i] <= last[j])
5005 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5006 printf(_("Warning: partition %d overlaps "
5007 "partition %d.\n"), j + 1, i + 1);
5008 total += first[i] >= first[j] ?
5009 first[i] : first[j];
5010 total -= last[i] <= last[j] ?
5011 last[i] : last[j];
5012 }
5013 }
5014 }
5015
5016 if (extended_offset) {
5017 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005018 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005019 get_nr_sects(pex->part_table) - 1;
5020
5021 for (i = 4; i < partitions; i++) {
5022 total++;
5023 p = ptes[i].part_table;
5024 if (!p->sys_ind) {
5025 if (i != 4 || i + 1 < partitions)
5026 printf(_("Warning: partition %d "
5027 "is empty\n"), i + 1);
5028 }
5029 else if (first[i] < extended_offset ||
5030 last[i] > e_last)
5031 printf(_("Logical partition %d not entirely in "
5032 "partition %d\n"), i + 1, ext_index + 1);
5033 }
5034 }
5035
5036 if (total > heads * sectors * cylinders)
5037 printf(_("Total allocated sectors %d greater than the maximum "
5038 "%d\n"), total, heads * sectors * cylinders);
5039 else if ((total = heads * sectors * cylinders - total) != 0)
5040 printf(_("%d unallocated sectors\n"), total);
5041}
5042
5043static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005044add_partition(int n, int sys)
5045{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005046 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005047 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005048 struct partition *p = ptes[n].part_table;
5049 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005050 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005051 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005052 first[partitions], last[partitions];
5053
5054 if (p && p->sys_ind) {
5055 printf(_("Partition %d is already defined. Delete "
5056 "it before re-adding it.\n"), n + 1);
5057 return;
5058 }
5059 fill_bounds(first, last);
5060 if (n < 4) {
5061 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005062 if (display_in_cyl_units || !total_number_of_sectors)
5063 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005064 else
Eric Andersen040f4402003-07-30 08:40:37 +00005065 llimit = total_number_of_sectors - 1;
5066 limit = llimit;
5067 if (limit != llimit)
5068 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005069 if (extended_offset) {
5070 first[ext_index] = extended_offset;
5071 last[ext_index] = get_start_sect(q) +
5072 get_nr_sects(q) - 1;
5073 }
5074 } else {
5075 start = extended_offset + sector_offset;
5076 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5077 }
5078 if (display_in_cyl_units)
5079 for (i = 0; i < partitions; i++)
5080 first[i] = (cround(first[i]) - 1) * units_per_sector;
5081
5082 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5083 do {
5084 temp = start;
5085 for (i = 0; i < partitions; i++) {
5086 int lastplusoff;
5087
5088 if (start == ptes[i].offset)
5089 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005090 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005091 if (start >= first[i] && start <= lastplusoff)
5092 start = lastplusoff + 1;
5093 }
5094 if (start > limit)
5095 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005096 if (start >= temp+units_per_sector && num_read) {
Eric Andersend9261492004-06-28 23:50:31 +00005097 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005098 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005099 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005100 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005101 if (!num_read && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005102 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005103
5104 saved_start = start;
5105 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5106 0, mesg);
5107 if (display_in_cyl_units) {
5108 start = (start - 1) * units_per_sector;
5109 if (start < saved_start) start = saved_start;
5110 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005111 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005112 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005113 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005114 if (n > 4) { /* NOT for fifth partition */
5115 struct pte *pe = &ptes[n];
5116
5117 pe->offset = start - sector_offset;
5118 if (pe->offset == extended_offset) { /* must be corrected */
5119 pe->offset++;
5120 if (sector_offset == 1)
5121 start++;
5122 }
5123 }
5124
5125 for (i = 0; i < partitions; i++) {
5126 struct pte *pe = &ptes[i];
5127
5128 if (start < pe->offset && limit >= pe->offset)
5129 limit = pe->offset - 1;
5130 if (start < first[i] && limit >= first[i])
5131 limit = first[i] - 1;
5132 }
5133 if (start > limit) {
5134 printf(_("No free sectors available\n"));
5135 if (n > 4)
5136 partitions--;
5137 return;
5138 }
5139 if (cround(start) == cround(limit)) {
5140 stop = limit;
5141 } else {
5142 snprintf(mesg, sizeof(mesg),
5143 _("Last %s or +size or +sizeM or +sizeK"),
5144 str_units(SINGULAR));
5145 stop = read_int(cround(start), cround(limit), cround(limit),
5146 cround(start), mesg);
5147 if (display_in_cyl_units) {
5148 stop = stop * units_per_sector - 1;
5149 if (stop >limit)
5150 stop = limit;
5151 }
5152 }
5153
5154 set_partition(n, 0, start, stop, sys);
5155 if (n > 4)
5156 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5157
Rob Landleyb73451d2006-02-24 16:29:00 +00005158 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005159 struct pte *pe4 = &ptes[4];
5160 struct pte *pen = &ptes[n];
5161
5162 ext_index = n;
5163 pen->ext_pointer = p;
5164 pe4->offset = extended_offset = start;
Rob Landley081e3842006-08-03 20:07:35 +00005165 pe4->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005166 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5167 pe4->ext_pointer = pe4->part_table + 1;
5168 pe4->changed = 1;
5169 partitions = 5;
5170 }
5171}
5172
5173static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005174add_logical(void)
5175{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005176 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5177 struct pte *pe = &ptes[partitions];
5178
Rob Landley081e3842006-08-03 20:07:35 +00005179 pe->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005180 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5181 pe->ext_pointer = pe->part_table + 1;
5182 pe->offset = 0;
5183 pe->changed = 1;
5184 partitions++;
5185 }
5186 add_partition(partitions - 1, LINUX_NATIVE);
5187}
5188
5189static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005190new_partition(void)
5191{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005192 int i, free_primary = 0;
5193
5194 if (warn_geometry())
5195 return;
5196
5197#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005198 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005199 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5200 return;
5201 }
5202#endif
5203#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005204 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005205 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5206 return;
5207 }
5208#endif
5209#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005210 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005211 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5212 "\n\tIf you want to add DOS-type partitions, create"
5213 "\n\ta new empty DOS partition table first. (Use o.)"
5214 "\n\tWARNING: "
5215 "This will destroy the present disk contents.\n"));
5216 return;
5217 }
5218#endif
5219
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005220 for (i = 0; i < 4; i++)
5221 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005222
Rob Landleyb73451d2006-02-24 16:29:00 +00005223 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005224 printf(_("The maximum number of partitions has been created\n"));
5225 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005226 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005227
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005228 if (!free_primary) {
5229 if (extended_offset)
5230 add_logical();
5231 else
5232 printf(_("You must delete some partition and add "
5233 "an extended partition first\n"));
5234 } else {
5235 char c, line[LINE_LENGTH];
5236 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5237 "partition (1-4)\n",
5238 "Command action", (extended_offset ?
5239 "l logical (5 or over)" : "e extended"));
5240 while (1) {
5241 if ((c = read_char(line)) == 'p' || c == 'P') {
5242 i = get_nonexisting_partition(0, 4);
5243 if (i >= 0)
5244 add_partition(i, LINUX_NATIVE);
5245 return;
5246 }
5247 else if (c == 'l' && extended_offset) {
5248 add_logical();
5249 return;
5250 }
5251 else if (c == 'e' && !extended_offset) {
5252 i = get_nonexisting_partition(0, 4);
5253 if (i >= 0)
5254 add_partition(i, EXTENDED);
5255 return;
5256 }
5257 else
5258 printf(_("Invalid partition number "
5259 "for type `%c'\n"), c);
5260 }
5261 }
5262}
5263
5264static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005265write_table(void)
5266{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005267 int i;
5268
Rob Landley5527b912006-02-25 03:46:10 +00005269 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005270 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005271 if (ptes[i].changed)
5272 ptes[3].changed = 1;
5273 for (i = 3; i < partitions; i++) {
5274 struct pte *pe = &ptes[i];
5275
5276 if (pe->changed) {
5277 write_part_table_flag(pe->sectorbuffer);
5278 write_sector(pe->offset, pe->sectorbuffer);
5279 }
5280 }
5281 }
5282#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005283 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005284 /* no test on change? the printf below might be mistaken */
5285 sgi_write_table();
5286 }
5287#endif
5288#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005289 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005290 int needw = 0;
5291
Rob Landleyb73451d2006-02-24 16:29:00 +00005292 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005293 if (ptes[i].changed)
5294 needw = 1;
5295 if (needw)
5296 sun_write_table();
5297 }
5298#endif
5299
5300 printf(_("The partition table has been altered!\n\n"));
5301 reread_partition_table(1);
5302}
5303
Rob Landleyb73451d2006-02-24 16:29:00 +00005304static void
5305reread_partition_table(int leave)
5306{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005307 int error = 0;
5308 int i;
5309
5310 printf(_("Calling ioctl() to re-read partition table.\n"));
5311 sync();
5312 sleep(2);
5313 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5314 error = errno;
5315 } else {
5316 /* some kernel versions (1.2.x) seem to have trouble
5317 rereading the partition table, but if asked to do it
5318 twice, the second time works. - biro@yggdrasil.com */
5319 sync();
5320 sleep(2);
5321 if ((i = ioctl(fd, BLKRRPART)) != 0)
5322 error = errno;
5323 }
5324
5325 if (i) {
5326 printf(_("\nWARNING: Re-reading the partition table "
5327 "failed with error %d: %s.\n"
5328 "The kernel still uses the old table.\n"
5329 "The new table will be used "
5330 "at the next reboot.\n"),
5331 error, strerror(error));
5332 }
5333
5334 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005335 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005336 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5337 "partitions, please see the fdisk manual page for additional\n"
5338 "information.\n"));
5339
5340 if (leave) {
5341 close(fd);
5342
5343 printf(_("Syncing disks.\n"));
5344 sync();
5345 sleep(4); /* for sync() */
5346 exit(!!i);
5347 }
5348}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005349#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005350
5351#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5352#define MAX_PER_LINE 16
5353static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005354print_buffer(char *pbuffer)
5355{
5356 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005357
5358 for (i = 0, l = 0; i < sector_size; i++, l++) {
5359 if (l == 0)
5360 printf("0x%03X:", i);
5361 printf(" %02X", (unsigned char) pbuffer[i]);
5362 if (l == MAX_PER_LINE - 1) {
5363 printf("\n");
5364 l = -1;
5365 }
5366 }
5367 if (l > 0)
5368 printf("\n");
5369 printf("\n");
5370}
5371
5372
5373static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005374print_raw(void)
5375{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005376 int i;
5377
5378 printf(_("Device: %s\n"), disk_device);
5379#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005380 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005381 print_buffer(MBRbuffer);
5382 else
5383#endif
5384 for (i = 3; i < partitions; i++)
5385 print_buffer(ptes[i].sectorbuffer);
5386}
5387
5388static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005389move_begin(int i)
5390{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005391 struct pte *pe = &ptes[i];
5392 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005393 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005394
5395 if (warn_geometry())
5396 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005397 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005398 printf(_("Partition %d has no data area\n"), i + 1);
5399 return;
5400 }
5401 first = get_partition_start(pe);
5402 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005403 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005404
5405 if (new != get_nr_sects(p)) {
5406 first = get_nr_sects(p) + get_start_sect(p) - new;
5407 set_nr_sects(p, first);
5408 set_start_sect(p, new);
5409 pe->changed = 1;
5410 }
5411}
5412
5413static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005414xselect(void)
5415{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005416 char c;
5417
Rob Landleyb73451d2006-02-24 16:29:00 +00005418 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005419 putchar('\n');
5420 c = tolower(read_char(_("Expert command (m for help): ")));
5421 switch (c) {
5422 case 'a':
5423#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005424 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005425 sun_set_alt_cyl();
5426#endif
5427 break;
5428 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005429 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005430 move_begin(get_partition(0, partitions));
5431 break;
5432 case 'c':
5433 user_cylinders = cylinders =
5434 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005435 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005436#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005437 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005438 sun_set_ncyl(cylinders);
5439#endif
Rob Landley5527b912006-02-25 03:46:10 +00005440 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005441 warn_cylinders();
5442 break;
5443 case 'd':
5444 print_raw();
5445 break;
5446 case 'e':
5447#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005448 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005449 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005450 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005451#endif
5452#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005453 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005454 sun_set_xcyl();
5455 else
5456#endif
Rob Landley5527b912006-02-25 03:46:10 +00005457 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005458 x_list_table(1);
5459 break;
5460 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005461 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005462 fix_partition_table_order();
5463 break;
5464 case 'g':
5465#ifdef CONFIG_FEATURE_SGI_LABEL
5466 create_sgilabel();
5467#endif
5468 break;
5469 case 'h':
5470 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005471 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005472 update_units();
5473 break;
5474 case 'i':
5475#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005476 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005477 sun_set_ilfact();
5478#endif
5479 break;
5480 case 'o':
5481#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005482 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005483 sun_set_rspeed();
5484#endif
5485 break;
5486 case 'p':
5487#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005488 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005489 list_table(1);
5490 else
5491#endif
5492 x_list_table(0);
5493 break;
5494 case 'q':
5495 close(fd);
5496 printf("\n");
5497 exit(0);
5498 case 'r':
5499 return;
5500 case 's':
5501 user_sectors = sectors = read_int(1, sectors, 63, 0,
5502 _("Number of sectors"));
5503 if (dos_compatible_flag) {
5504 sector_offset = sectors;
5505 fprintf(stderr, _("Warning: setting "
5506 "sector offset for DOS "
5507 "compatiblity\n"));
5508 }
5509 update_units();
5510 break;
5511 case 'v':
5512 verify();
5513 break;
5514 case 'w':
5515 write_table(); /* does not return */
5516 break;
5517 case 'y':
5518#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005519 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005520 sun_set_pcylcount();
5521#endif
5522 break;
5523 default:
5524 xmenu();
5525 }
5526 }
5527}
5528#endif /* ADVANCED mode */
5529
5530static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005531is_ide_cdrom_or_tape(const char *device)
5532{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005533 FILE *procf;
5534 char buf[100];
5535 struct stat statbuf;
5536 int is_ide = 0;
5537
5538 /* No device was given explicitly, and we are trying some
5539 likely things. But opening /dev/hdc may produce errors like
5540 "hdc: tray open or drive not ready"
5541 if it happens to be a CD-ROM drive. It even happens that
5542 the process hangs on the attempt to read a music CD.
5543 So try to be careful. This only works since 2.1.73. */
5544
5545 if (strncmp("/dev/hd", device, 7))
5546 return 0;
5547
5548 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5549 procf = fopen(buf, "r");
5550 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5551 is_ide = (!strncmp(buf, "cdrom", 5) ||
5552 !strncmp(buf, "tape", 4));
5553 else
5554 /* Now when this proc file does not exist, skip the
5555 device when it is read-only. */
5556 if (stat(device, &statbuf) == 0)
5557 is_ide = ((statbuf.st_mode & 0222) == 0);
5558
5559 if (procf)
5560 fclose(procf);
5561 return is_ide;
5562}
5563
Rob Landley5527b912006-02-25 03:46:10 +00005564
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005565static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005566try(const char *device, int user_specified)
5567{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005568 int gb;
5569
5570 disk_device = device;
5571 if (setjmp(listingbuf))
5572 return;
5573 if (!user_specified)
5574 if (is_ide_cdrom_or_tape(device))
5575 return;
5576 if ((fd = open(disk_device, type_open)) >= 0) {
5577 gb = get_boot(try_only);
5578 if (gb > 0) { /* I/O error */
5579 close(fd);
5580 } else if (gb < 0) { /* no DOS signature */
5581 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005582 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005583 return;
Rob Landley5527b912006-02-25 03:46:10 +00005584 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005585#ifdef CONFIG_FEATURE_OSF_LABEL
5586 if (btrydev(device) < 0)
5587#endif
5588 fprintf(stderr,
5589 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005590 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005591 close(fd);
5592 } else {
5593 close(fd);
5594 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005595#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005596 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005597 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005598 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005599#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005600 }
5601 } else {
5602 /* Ignore other errors, since we try IDE
5603 and SCSI hard disks which may not be
5604 installed on the system. */
5605 if (errno == EACCES) {
5606 fprintf(stderr, _("Cannot open %s\n"), device);
5607 return;
5608 }
5609 }
5610}
5611
5612/* for fdisk -l: try all things in /proc/partitions
5613 that look like a partition name (do not end in a digit) */
5614static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005615tryprocpt(void)
5616{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005617 FILE *procpt;
5618 char line[100], ptname[100], devname[120], *s;
5619 int ma, mi, sz;
5620
Manuel Novoa III cad53642003-03-19 09:13:01 +00005621 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005622
5623 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005624 if (sscanf(line, " %d %d %d %[^\n ]",
5625 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005626 continue;
5627 for (s = ptname; *s; s++);
5628 if (isdigit(s[-1]))
5629 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005630 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005631 try(devname, 0);
5632 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005633#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005634 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005635#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005636}
5637
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005638#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005639static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005640unknown_command(int c)
5641{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005642 printf(_("%c: unknown command\n"), c);
5643}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005644#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005645
Rob Landleyb73451d2006-02-24 16:29:00 +00005646int fdisk_main(int argc, char **argv)
5647{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005648 int c;
5649#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5650 int optl = 0;
5651#endif
5652#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5653 int opts = 0;
5654#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005655 /*
5656 * Calls:
5657 * fdisk -v
5658 * fdisk -l [-b sectorsize] [-u] device ...
5659 * fdisk -s [partition] ...
5660 * fdisk [-b sectorsize] [-u] device
5661 *
5662 * Options -C, -H, -S set the geometry.
5663 *
5664 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005665 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5666#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5667 "s"
5668#endif
5669 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005670 switch (c) {
5671 case 'b':
5672 /* Ugly: this sector size is really per device,
5673 so cannot be combined with multiple disks,
5674 and te same goes for the C/H/S options.
5675 */
5676 sector_size = atoi(optarg);
5677 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005678 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005679 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005680 sector_offset = 2;
5681 user_set_sector_size = 1;
5682 break;
5683 case 'C':
5684 user_cylinders = atoi(optarg);
5685 break;
5686 case 'H':
5687 user_heads = atoi(optarg);
5688 if (user_heads <= 0 || user_heads >= 256)
5689 user_heads = 0;
5690 break;
5691 case 'S':
5692 user_sectors = atoi(optarg);
5693 if (user_sectors <= 0 || user_sectors >= 64)
5694 user_sectors = 0;
5695 break;
5696 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005697#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005698 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005699#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005700 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005701#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005702 case 's':
5703 opts = 1;
5704 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005705#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005706 case 'u':
5707 display_in_cyl_units = 0;
5708 break;
5709 case 'V':
5710 case 'v':
5711 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5712 return 0;
5713 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005714 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005715 }
5716 }
5717
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005718 if (user_set_sector_size && argc-optind != 1)
5719 printf(_("Warning: the -b (set sector size) option should"
5720 " be used with one specified device\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005721
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005722#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005723 if (optl) {
5724 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005725#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005726 type_open = O_RDONLY;
5727 if (argc > optind) {
5728 int k;
5729#if __GNUC__
5730 /* avoid gcc warning:
5731 variable `k' might be clobbered by `longjmp' */
5732 (void)&k;
5733#endif
5734 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005735 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005736 try(argv[k], 1);
5737 } else {
5738 /* we no longer have default device names */
5739 /* but, we can use /proc/partitions instead */
5740 tryprocpt();
5741 }
5742 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005743#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005744 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005745#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005746
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005747#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005748 if (opts) {
5749 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005750 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005751
5752 nowarn = 1;
5753 type_open = O_RDONLY;
5754
5755 opts = argc - optind;
5756 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005757 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005758
5759 for (j = optind; j < argc; j++) {
5760 disk_device = argv[j];
5761 if ((fd = open(disk_device, type_open)) < 0)
5762 fdisk_fatal(unable_to_open);
5763 if (ioctl(fd, BLKGETSIZE, &size))
5764 fdisk_fatal(ioctl_error);
5765 close(fd);
5766 if (opts == 1)
5767 printf("%ld\n", size/2);
5768 else
5769 printf("%s: %ld\n", argv[j], size/2);
5770 }
5771 return 0;
5772 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005773#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005774
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005775#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005776 if (argc-optind == 1)
5777 disk_device = argv[optind];
5778 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005779 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005780
5781 get_boot(fdisk);
5782
5783#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005784 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005785 /* OSF label, and no DOS label */
5786 printf(_("Detected an OSF/1 disklabel on %s, entering "
5787 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005788 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005789 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005790 /*Why do we do this? It seems to be counter-intuitive*/
5791 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005792 /* If we return we may want to make an empty DOS label? */
5793 }
5794#endif
5795
5796 while (1) {
5797 putchar('\n');
5798 c = tolower(read_char(_("Command (m for help): ")));
5799 switch (c) {
5800 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005801 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005802 toggle_active(get_partition(1, partitions));
5803#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005804 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005805 toggle_sunflags(get_partition(1, partitions),
5806 0x01);
5807#endif
5808#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005809 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005810 sgi_set_bootpartition(
5811 get_partition(1, partitions));
5812#endif
5813 else
5814 unknown_command(c);
5815 break;
5816 case 'b':
5817#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005818 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005819 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005820 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005821 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005822 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005823 printf(_("Boot file unchanged\n"));
5824 else
5825 sgi_set_bootfile(line_ptr);
5826 } else
5827#endif
5828#ifdef CONFIG_FEATURE_OSF_LABEL
5829 bselect();
5830#endif
5831 break;
5832 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005833 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005834 toggle_dos_compatibility_flag();
5835#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005836 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005837 toggle_sunflags(get_partition(1, partitions),
5838 0x10);
5839#endif
5840#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005841 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005842 sgi_set_swappartition(
5843 get_partition(1, partitions));
5844#endif
5845 else
5846 unknown_command(c);
5847 break;
5848 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005849 {
Eric Andersen040f4402003-07-30 08:40:37 +00005850 int j;
5851#ifdef CONFIG_FEATURE_SGI_LABEL
5852 /* If sgi_label then don't use get_existing_partition,
5853 let the user select a partition, since
5854 get_existing_partition() only works for Linux-like
5855 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005856 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005857 j = get_existing_partition(1, partitions);
5858 } else {
5859 j = get_partition(1, partitions);
5860 }
5861#else
5862 j = get_existing_partition(1, partitions);
5863#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005864 if (j >= 0)
5865 delete_partition(j);
5866 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005867 break;
5868 case 'i':
5869#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005870 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005871 create_sgiinfo();
5872 else
5873#endif
5874 unknown_command(c);
5875 case 'l':
5876 list_types(get_sys_types());
5877 break;
5878 case 'm':
5879 menu();
5880 break;
5881 case 'n':
5882 new_partition();
5883 break;
5884 case 'o':
5885 create_doslabel();
5886 break;
5887 case 'p':
5888 list_table(0);
5889 break;
5890 case 'q':
5891 close(fd);
5892 printf("\n");
5893 return 0;
5894 case 's':
5895#ifdef CONFIG_FEATURE_SUN_LABEL
5896 create_sunlabel();
5897#endif
5898 break;
5899 case 't':
5900 change_sysid();
5901 break;
5902 case 'u':
5903 change_units();
5904 break;
5905 case 'v':
5906 verify();
5907 break;
5908 case 'w':
5909 write_table(); /* does not return */
5910 break;
5911#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5912 case 'x':
5913#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005914 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005915 fprintf(stderr,
5916 _("\n\tSorry, no experts menu for SGI "
5917 "partition tables available.\n\n"));
5918 } else
5919#endif
5920
5921 xselect();
5922 break;
5923#endif
5924 default:
5925 unknown_command(c);
5926 menu();
5927 }
5928 }
5929 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005930#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005931}