blob: 26ec2e3634fd1c964ca9361be926063131cd583a [file] [log] [blame]
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
Mike Frysinger983e0ca2006-02-25 07:42:02 +00004 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005 *
Rob Landleyb73451d2006-02-24 16:29:00 +00006 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00007 */
8
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +00009/* Current changes have not compatibility with this version */
Eric Andersen99a75d12003-08-08 20:04:56 +000010#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000011
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000012
Rob Landley15d20a02006-05-29 05:00:44 +000013#define _(x) x
14
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000015#define PROC_PARTITIONS "/proc/partitions"
16
Eric Andersen256c4fd2004-05-19 09:00:00 +000017#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000018#include <sys/types.h>
19#include <sys/stat.h> /* stat */
20#include <ctype.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <errno.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <setjmp.h>
28#include <assert.h> /* assert */
29#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000031#include <sys/ioctl.h>
32#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000033#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000034
Eric Andersenacd244a2002-12-11 03:49:33 +000035#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
36
37/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000038#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000039
40#include <sys/utsname.h>
41
42#include "busybox.h"
43
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000044#define DKTYPENAMES
45
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000046#define BLKRRPART _IO(0x12,95) /* re-read partition table */
47#define BLKGETSIZE _IO(0x12,96) /* return device size */
48#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
49#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000050
51/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000052 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000053#undef _IOR
54#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000055#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000056
57/*
58 fdisk.h
59*/
60
61#define DEFAULT_SECTOR_SIZE 512
62#define MAX_SECTOR_SIZE 2048
63#define SECTOR_SIZE 512 /* still used in BSD code */
64#define MAXIMUM_PARTS 60
65
66#define ACTIVE_FLAG 0x80
67
68#define EXTENDED 0x05
69#define WIN98_EXTENDED 0x0f
70#define LINUX_PARTITION 0x81
71#define LINUX_SWAP 0x82
72#define LINUX_NATIVE 0x83
73#define LINUX_EXTENDED 0x85
74#define LINUX_LVM 0x8e
75#define LINUX_RAID 0xfd
76
77#define SUNOS_SWAP 3
78#define WHOLE_DISK 5
79
80#define IS_EXTENDED(i) \
81 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
82
83#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
84
85#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
86#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
87
Eric Andersen7495b0d2004-02-06 05:26:58 +000088#ifdef CONFIG_FEATURE_SUN_LABEL
89#define SCSI_IOCTL_GET_IDLUN 0x5382
90#endif
91
Eric Andersend3652bf2003-08-06 09:07:37 +000092
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000093/* including <linux/hdreg.h> also fails */
94struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000095 unsigned char heads;
96 unsigned char sectors;
97 unsigned short cylinders;
98 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000099};
100
101#define HDIO_GETGEO 0x0301 /* get device geometry */
102
103
104struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000105 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000106};
107
Rob Landleyb73451d2006-02-24 16:29:00 +0000108static uint sector_size = DEFAULT_SECTOR_SIZE;
109static uint user_set_sector_size;
110static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000111
112/*
113 * Raw disk label. For DOS-type partition tables the MBR,
114 * with descriptions of the primary partitions.
115 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000116#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000117static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000118#else
119# define MBRbuffer bb_common_bufsiz1
120#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000121
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000122#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000123static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000124#endif
125
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000126static uint heads, sectors, cylinders;
127static void update_units(void);
128
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000129
130/*
131 * return partition name - uses static storage unless buf is supplied
132 */
133static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000134partname(const char *dev, int pno, int lth)
135{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000136 static char buffer[80];
137 const char *p;
138 int w, wp;
139 int bufsiz;
140 char *bufp;
141
142 bufp = buffer;
143 bufsiz = sizeof(buffer);
144
145 w = strlen(dev);
146 p = "";
147
148 if (isdigit(dev[w-1]))
149 p = "p";
150
151 /* devfs kludge - note: fdisk partition names are not supposed
152 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000153 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000154 w -= 4;
155 p = "part";
156 }
157
158 wp = strlen(p);
159
160 if (lth) {
161 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
162 lth-wp-2, w, dev, p, pno);
163 } else {
164 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
165 }
166 return bufp;
167}
168
169struct partition {
170 unsigned char boot_ind; /* 0x80 - active */
171 unsigned char head; /* starting head */
172 unsigned char sector; /* starting sector */
173 unsigned char cyl; /* starting cylinder */
174 unsigned char sys_ind; /* What partition type */
175 unsigned char end_head; /* end head */
176 unsigned char end_sector; /* end sector */
177 unsigned char end_cyl; /* end cylinder */
178 unsigned char start4[4]; /* starting sector counting from 0 */
179 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000180} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000181
182enum failure {
183 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
184 unable_to_write
185};
186
Rob Landley5527b912006-02-25 03:46:10 +0000187enum label_type{
188 label_dos, label_sun, label_sgi, label_aix, label_osf
189};
190
Rob Landleyb73451d2006-02-24 16:29:00 +0000191enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000192
Rob Landley5527b912006-02-25 03:46:10 +0000193static enum label_type current_label_type;
194
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000195static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000196static int fd; /* the disk */
197static int partitions = 4; /* maximum partition + 1 */
198static uint display_in_cyl_units = 1;
199static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000200#ifdef CONFIG_FEATURE_FDISK_WRITABLE
201static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000202static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000203static void reread_partition_table(int leave);
204static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000205static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000206static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000207static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000208#endif
209static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000210static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000211static void get_geometry(void);
212static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000213
214#define PLURAL 0
215#define SINGULAR 1
216
217#define hex_val(c) ({ \
218 char _c = (c); \
219 isdigit(_c) ? _c - '0' : \
220 tolower(_c) + 10 - 'a'; \
221 })
222
223
224#define LINE_LENGTH 800
225#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
226 (n) * sizeof(struct partition)))
227#define sector(s) ((s) & 0x3f)
228#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
229
230#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
231 ((h) + heads * cylinder(s,c)))
232#define set_hsc(h,s,c,sector) { \
233 s = sector % sectors + 1; \
234 sector /= sectors; \
235 h = sector % heads; \
236 sector /= heads; \
237 c = sector & 0xff; \
238 s |= (sector >> 2) & 0xc0; \
239 }
240
241
Eric Andersend9261492004-06-28 23:50:31 +0000242static int32_t get_start_sect(const struct partition *p);
243static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000244
245/*
246 * per partition table entry data
247 *
248 * The four primary partitions have the same sectorbuffer (MBRbuffer)
249 * and have NULL ext_pointer.
250 * Each logical partition table entry has two pointers, one for the
251 * partition and one link to the next one.
252 */
253static struct pte {
254 struct partition *part_table; /* points into sectorbuffer */
255 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000256#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000257 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000258#endif
Eric Andersend9261492004-06-28 23:50:31 +0000259 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000260 char *sectorbuffer; /* disk sector contents */
261} ptes[MAXIMUM_PARTS];
262
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000263
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000264#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000265static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000266set_all_unchanged(void)
267{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000268 int i;
269
270 for (i = 0; i < MAXIMUM_PARTS; i++)
271 ptes[i].changed = 0;
272}
273
274static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000275set_changed(int i)
276{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000277 ptes[i].changed = 1;
278}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000279#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000280
281#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
282static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000283get_part_table(int i)
284{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000285 return ptes[i].part_table;
286}
287#endif
288
289static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000290str_units(int n)
291{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000292 if (n == 1)
293 return display_in_cyl_units ? _("cylinder") : _("sector");
294 else
295 return display_in_cyl_units ? _("cylinders") : _("sectors");
296}
297
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000298static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000299valid_part_table_flag(const char *mbuffer) {
300 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000301 return (b[510] == 0x55 && b[511] == 0xaa);
302}
303
304#ifdef CONFIG_FEATURE_FDISK_WRITABLE
305static char line_buffer[LINE_LENGTH];
306
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000307/* read line; return 0 or first char */
308static int
309read_line(void)
310{
311 static int got_eof = 0;
312
313 fflush (stdout); /* requested by niles@scyld.com */
314 line_ptr = line_buffer;
315 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
316 if (feof(stdin))
317 got_eof++; /* user typed ^D ? */
318 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000319 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
320 exit(1);
321 }
322 return 0;
323 }
324 while (*line_ptr && !isgraph(*line_ptr))
325 line_ptr++;
326 return *line_ptr;
327}
328
329static char
330read_char(const char *mesg)
331{
332 do {
333 fputs(mesg, stdout);
334 } while (!read_line());
335 return *line_ptr;
336}
337
338static char
339read_chars(const char *mesg)
340{
341 fputs(mesg, stdout);
342 if (!read_line()) {
343 *line_ptr = '\n';
344 line_ptr[1] = 0;
345 }
346 return *line_ptr;
347}
348
349static int
350read_hex(const struct systypes *sys)
351{
352 int hex;
353
Rob Landleyb73451d2006-02-24 16:29:00 +0000354 while (1) {
355 read_char(_("Hex code (type L to list codes): "));
356 if (*line_ptr == 'l' || *line_ptr == 'L')
357 list_types(sys);
358 else if (isxdigit (*line_ptr)) {
359 hex = 0;
360 do
361 hex = hex << 4 | hex_val(*line_ptr++);
362 while (isxdigit(*line_ptr));
363 return hex;
364 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000365 }
366}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000367#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000368
369#ifdef CONFIG_FEATURE_AIX_LABEL
370/*
371 * Copyright (C) Andreas Neuper, Sep 1998.
372 * This file may be redistributed under
373 * the terms of the GNU Public License.
374 */
375
376typedef struct {
377 unsigned int magic; /* expect AIX_LABEL_MAGIC */
378 unsigned int fillbytes1[124];
379 unsigned int physical_volume_id;
380 unsigned int fillbytes2[124];
381} aix_partition;
382
383#define AIX_LABEL_MAGIC 0xc9c2d4c1
384#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
385#define AIX_INFO_MAGIC 0x00072959
386#define AIX_INFO_MAGIC_SWAPPED 0x59290700
387
388#define aixlabel ((aix_partition *)MBRbuffer)
389
390
391/*
392 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000393 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
394 * Internationalization
395 *
396 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
397 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000398*/
399
Rob Landleyb73451d2006-02-24 16:29:00 +0000400static int aix_other_endian;
401static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000402
403/*
404 * only dealing with free blocks here
405 */
406
407static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000408aix_info(void)
409{
410 puts(
411 _("\n\tThere is a valid AIX label on this disk.\n"
412 "\tUnfortunately Linux cannot handle these\n"
413 "\tdisks at the moment. Nevertheless some\n"
414 "\tadvice:\n"
415 "\t1. fdisk will destroy its contents on write.\n"
416 "\t2. Be sure that this disk is NOT a still vital\n"
417 "\t part of a volume group. (Otherwise you may\n"
418 "\t erase the other disks as well, if unmirrored.)\n"
419 "\t3. Before deleting this physical volume be sure\n"
420 "\t to remove the disk logically from your AIX\n"
421 "\t machine. (Otherwise you become an AIXpert).")
422 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000423}
424
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000425static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000426check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000427{
Rob Landleyb73451d2006-02-24 16:29:00 +0000428 if (aixlabel->magic != AIX_LABEL_MAGIC &&
429 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000430 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000431 aix_other_endian = 0;
432 return 0;
433 }
434 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
435 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000436 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000437 partitions = 1016;
438 aix_volumes = 15;
439 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000440 /*aix_nolabel();*/ /* %% */
441 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000442 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000443}
444#endif /* AIX_LABEL */
445
446#ifdef CONFIG_FEATURE_OSF_LABEL
447/*
448 * Copyright (c) 1987, 1988 Regents of the University of California.
449 * All rights reserved.
450 *
451 * Redistribution and use in source and binary forms, with or without
452 * modification, are permitted provided that the following conditions
453 * are met:
454 * 1. Redistributions of source code must retain the above copyright
455 * notice, this list of conditions and the following disclaimer.
456 * 2. Redistributions in binary form must reproduce the above copyright
457 * notice, this list of conditions and the following disclaimer in the
458 * documentation and/or other materials provided with the distribution.
459 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000460 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000461 * This product includes software developed by the University of
462 * California, Berkeley and its contributors.
463 * 4. Neither the name of the University nor the names of its contributors
464 * may be used to endorse or promote products derived from this software
465 * without specific prior written permission.
466 *
467 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
468 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
469 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
470 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
471 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
472 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
473 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
474 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
475 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
476 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
477 * SUCH DAMAGE.
478 */
479
480
481#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000482#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000483#endif
484
485#ifndef BSD_MAXPARTITIONS
486#define BSD_MAXPARTITIONS 16
487#endif
488
489#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
490
491#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
492#define BSD_LABELSECTOR 1
493#define BSD_LABELOFFSET 0
494#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
495#define BSD_LABELSECTOR 0
496#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000497#elif defined (__s390__) || defined (__s390x__)
498#define BSD_LABELSECTOR 1
499#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000500#else
501#error unknown architecture
502#endif
503
504#define BSD_BBSIZE 8192 /* size of boot area, with label */
505#define BSD_SBSIZE 8192 /* max size of fs superblock */
506
507struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000508 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000509 int16_t d_type; /* drive type */
510 int16_t d_subtype; /* controller/d_type specific */
511 char d_typename[16]; /* type name, e.g. "eagle" */
512 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000513 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000514 uint32_t d_secsize; /* # of bytes per sector */
515 uint32_t d_nsectors; /* # of data sectors per track */
516 uint32_t d_ntracks; /* # of tracks per cylinder */
517 uint32_t d_ncylinders; /* # of data cylinders per unit */
518 uint32_t d_secpercyl; /* # of data sectors per cylinder */
519 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000520 /*
521 * Spares (bad sector replacements) below
522 * are not counted in d_nsectors or d_secpercyl.
523 * Spare sectors are assumed to be physical sectors
524 * which occupy space at the end of each track and/or cylinder.
525 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000526 uint16_t d_sparespertrack; /* # of spare sectors per track */
527 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000528 /*
529 * Alternate cylinders include maintenance, replacement,
530 * configuration description areas, etc.
531 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000532 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000533
534 /* hardware characteristics: */
535 /*
536 * d_interleave, d_trackskew and d_cylskew describe perturbations
537 * in the media format used to compensate for a slow controller.
538 * Interleave is physical sector interleave, set up by the formatter
539 * or controller when formatting. When interleaving is in use,
540 * logically adjacent sectors are not physically contiguous,
541 * but instead are separated by some number of sectors.
542 * It is specified as the ratio of physical sectors traversed
543 * per logical sector. Thus an interleave of 1:1 implies contiguous
544 * layout, while 2:1 implies that logical sector 0 is separated
545 * by one sector from logical sector 1.
546 * d_trackskew is the offset of sector 0 on track N
547 * relative to sector 0 on track N-1 on the same cylinder.
548 * Finally, d_cylskew is the offset of sector 0 on cylinder N
549 * relative to sector 0 on cylinder N-1.
550 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000551 uint16_t d_rpm; /* rotational speed */
552 uint16_t d_interleave; /* hardware sector interleave */
553 uint16_t d_trackskew; /* sector 0 skew, per track */
554 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
555 uint32_t d_headswitch; /* head switch time, usec */
556 uint32_t d_trkseek; /* track-to-track seek, usec */
557 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000558#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000559 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000560#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000561 uint32_t d_spare[NSPARE]; /* reserved for future use */
562 uint32_t d_magic2; /* the magic number (again) */
563 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000564 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000565 uint16_t d_npartitions; /* number of partitions in following */
566 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
567 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000568 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000569 uint32_t p_size; /* number of sectors in partition */
570 uint32_t p_offset; /* starting sector */
571 uint32_t p_fsize; /* filesystem basic fragment size */
572 uint8_t p_fstype; /* filesystem type, see below */
573 uint8_t p_frag; /* filesystem fragments per block */
574 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000575 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
576};
577
578/* d_type values: */
579#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
580#define BSD_DTYPE_MSCP 2 /* MSCP */
581#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
582#define BSD_DTYPE_SCSI 4 /* SCSI */
583#define BSD_DTYPE_ESDI 5 /* ESDI interface */
584#define BSD_DTYPE_ST506 6 /* ST506 etc. */
585#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
586#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
587#define BSD_DTYPE_FLOPPY 10 /* floppy */
588
589/* d_subtype values: */
590#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
591#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
592#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
593
594#ifdef DKTYPENAMES
595static const char * const xbsd_dktypenames[] = {
596 "unknown",
597 "SMD",
598 "MSCP",
599 "old DEC",
600 "SCSI",
601 "ESDI",
602 "ST506",
603 "HP-IB",
604 "HP-FL",
605 "type 9",
606 "floppy",
607 0
608};
609#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
610#endif
611
612/*
613 * Filesystem type and version.
614 * Used to interpret other filesystem-specific
615 * per-partition information.
616 */
617#define BSD_FS_UNUSED 0 /* unused */
618#define BSD_FS_SWAP 1 /* swap */
619#define BSD_FS_V6 2 /* Sixth Edition */
620#define BSD_FS_V7 3 /* Seventh Edition */
621#define BSD_FS_SYSV 4 /* System V */
622#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
623#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
624#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
625#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
626#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
627#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
628#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
629#define BSD_FS_ISOFS BSD_FS_ISO9660
630#define BSD_FS_BOOT 13 /* partition contains bootstrap */
631#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
632#define BSD_FS_HFS 15 /* Macintosh HFS */
633#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
634
635/* this is annoying, but it's also the way it is :-( */
636#ifdef __alpha__
637#define BSD_FS_EXT2 8 /* ext2 file system */
638#else
639#define BSD_FS_MSDOS 8 /* MS-DOS file system */
640#endif
641
642#ifdef DKTYPENAMES
643static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000644 { "\x00" "unused" }, /* BSD_FS_UNUSED */
645 { "\x01" "swap" }, /* BSD_FS_SWAP */
646 { "\x02" "Version 6" }, /* BSD_FS_V6 */
647 { "\x03" "Version 7" }, /* BSD_FS_V7 */
648 { "\x04" "System V" }, /* BSD_FS_SYSV */
649 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
650 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
651 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000652#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000653 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000654#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000655 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000656#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000657 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
658 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
659 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
660 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
661 { "\x0d" "boot" }, /* BSD_FS_BOOT */
662 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
663 { "\x0f" "HFS" }, /* BSD_FS_HFS */
664 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
665 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000666};
667#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
668
669#endif
670
671/*
672 * flags shared by various drives:
673 */
674#define BSD_D_REMOVABLE 0x01 /* removable media */
675#define BSD_D_ECC 0x02 /* supports ECC */
676#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
677#define BSD_D_RAMDISK 0x08 /* disk emulator */
678#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
679#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
680
681#endif /* OSF_LABEL */
682
683/*
684 * Copyright (C) Andreas Neuper, Sep 1998.
685 * This file may be modified and redistributed under
686 * the terms of the GNU Public License.
687 */
688
689struct device_parameter { /* 48 bytes */
690 unsigned char skew;
691 unsigned char gap1;
692 unsigned char gap2;
693 unsigned char sparecyl;
694 unsigned short pcylcount;
695 unsigned short head_vol0;
696 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
697 unsigned char cmd_tag_queue_depth;
698 unsigned char unused0;
699 unsigned short unused1;
700 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
701 unsigned short bytes;
702 unsigned short ilfact;
703 unsigned int flags; /* controller flags */
704 unsigned int datarate;
705 unsigned int retries_on_error;
706 unsigned int ms_per_word;
707 unsigned short xylogics_gap1;
708 unsigned short xylogics_syncdelay;
709 unsigned short xylogics_readdelay;
710 unsigned short xylogics_gap2;
711 unsigned short xylogics_readgate;
712 unsigned short xylogics_writecont;
713};
714
715#define SGI_VOLHDR 0x00
716/* 1 and 2 were used for drive types no longer supported by SGI */
717#define SGI_SWAP 0x03
718/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
719#define SGI_VOLUME 0x06
720#define SGI_EFS 0x07
721#define SGI_LVOL 0x08
722#define SGI_RLVOL 0x09
723#define SGI_XFS 0x0a
724#define SGI_XFSLOG 0x0b
725#define SGI_XLV 0x0c
726#define SGI_XVM 0x0d
727#define ENTIRE_DISK SGI_VOLUME
728/*
729 * controller flags
730 */
731#define SECTOR_SLIP 0x01
732#define SECTOR_FWD 0x02
733#define TRACK_FWD 0x04
734#define TRACK_MULTIVOL 0x08
735#define IGNORE_ERRORS 0x10
736#define RESEEK 0x20
737#define ENABLE_CMDTAGQ 0x40
738
739typedef struct {
740 unsigned int magic; /* expect SGI_LABEL_MAGIC */
741 unsigned short boot_part; /* active boot partition */
742 unsigned short swap_part; /* active swap partition */
743 unsigned char boot_file[16]; /* name of the bootfile */
744 struct device_parameter devparam; /* 1 * 48 bytes */
745 struct volume_directory { /* 15 * 16 bytes */
746 unsigned char vol_file_name[8]; /* a character array */
747 unsigned int vol_file_start; /* number of logical block */
748 unsigned int vol_file_size; /* number of bytes */
749 } directory[15];
750 struct sgi_partition { /* 16 * 12 bytes */
751 unsigned int num_sectors; /* number of blocks */
752 unsigned int start_sector; /* must be cylinder aligned */
753 unsigned int id;
754 } partitions[16];
755 unsigned int csum;
756 unsigned int fillbytes;
757} sgi_partition;
758
759typedef struct {
760 unsigned int magic; /* looks like a magic number */
761 unsigned int a2;
762 unsigned int a3;
763 unsigned int a4;
764 unsigned int b1;
765 unsigned short b2;
766 unsigned short b3;
767 unsigned int c[16];
768 unsigned short d[3];
769 unsigned char scsi_string[50];
770 unsigned char serial[137];
771 unsigned short check1816;
772 unsigned char installer[225];
773} sgiinfo;
774
775#define SGI_LABEL_MAGIC 0x0be5a941
776#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
777#define SGI_INFO_MAGIC 0x00072959
778#define SGI_INFO_MAGIC_SWAPPED 0x59290700
779#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000780 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000781#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000782 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000783
784#define sgilabel ((sgi_partition *)MBRbuffer)
785#define sgiparam (sgilabel->devparam)
786
787typedef struct {
788 unsigned char info[128]; /* Informative text string */
789 unsigned char spare0[14];
790 struct sun_info {
791 unsigned char spare1;
792 unsigned char id;
793 unsigned char spare2;
794 unsigned char flags;
795 } infos[8];
796 unsigned char spare1[246]; /* Boot information etc. */
797 unsigned short rspeed; /* Disk rotational speed */
798 unsigned short pcylcount; /* Physical cylinder count */
799 unsigned short sparecyl; /* extra sects per cylinder */
800 unsigned char spare2[4]; /* More magic... */
801 unsigned short ilfact; /* Interleave factor */
802 unsigned short ncyl; /* Data cylinder count */
803 unsigned short nacyl; /* Alt. cylinder count */
804 unsigned short ntrks; /* Tracks per cylinder */
805 unsigned short nsect; /* Sectors per track */
806 unsigned char spare3[4]; /* Even more magic... */
807 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000808 uint32_t start_cylinder;
809 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000810 } partitions[8];
811 unsigned short magic; /* Magic number */
812 unsigned short csum; /* Label xor'd checksum */
813} sun_partition;
814
Eric Andersen040f4402003-07-30 08:40:37 +0000815
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000816#define SUN_LABEL_MAGIC 0xDABE
817#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
818#define sunlabel ((sun_partition *)MBRbuffer)
819#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000820 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000821#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000822 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000823
Eric Andersend3652bf2003-08-06 09:07:37 +0000824
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000825#ifdef CONFIG_FEATURE_OSF_LABEL
826/*
827 Changes:
828 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
829
830 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
831 support for OSF/1 disklabels on Alpha.
832 Also fixed unaligned accesses in alpha_bootblock_checksum()
833*/
834
835#define FREEBSD_PARTITION 0xa5
836#define NETBSD_PARTITION 0xa9
837
Rob Landleyb73451d2006-02-24 16:29:00 +0000838static void xbsd_delete_part(void);
839static void xbsd_new_part(void);
840static void xbsd_write_disklabel(void);
841static int xbsd_create_disklabel(void);
842static void xbsd_edit_disklabel(void);
843static void xbsd_write_bootstrap(void);
844static void xbsd_change_fstype(void);
845static int xbsd_get_part_index(int max);
846static int xbsd_check_new_partition(int *i);
847static void xbsd_list_types(void);
848static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
849static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
850static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
851static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000852
853#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000854static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000855#endif
856
857#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000858static int xbsd_translate_fstype(int linux_type);
859static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000860static struct partition *xbsd_part;
861static int xbsd_part_index;
862#endif
863
864#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000865/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000866static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000867#else
868static char disklabelbuffer[BSD_BBSIZE];
869#endif
870
871static struct xbsd_disklabel xbsd_dlabel;
872
873#define bsd_cround(n) \
874 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
875
876/*
877 * Test whether the whole disk has BSD disk label magic.
878 *
879 * Note: often reformatting with DOS-type label leaves the BSD magic,
880 * so this does not mean that there is a BSD disk label.
881 */
882static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000883check_osf_label(void)
884{
885 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000886 return 0;
887 return 1;
888}
889
890static void xbsd_print_disklabel(int);
891
892static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000893btrydev(const char * dev)
894{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000895 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
896 return -1;
897 printf(_("\nBSD label for device: %s\n"), dev);
898 xbsd_print_disklabel (0);
899 return 0;
900}
901
902static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000903bmenu(void)
904{
905 puts (_("Command action"));
906 puts (_("\td\tdelete a BSD partition"));
907 puts (_("\te\tedit drive data"));
908 puts (_("\ti\tinstall bootstrap"));
909 puts (_("\tl\tlist known filesystem types"));
910 puts (_("\tm\tprint this menu"));
911 puts (_("\tn\tadd a new BSD partition"));
912 puts (_("\tp\tprint BSD partition table"));
913 puts (_("\tq\tquit without saving changes"));
914 puts (_("\tr\treturn to main menu"));
915 puts (_("\ts\tshow complete disklabel"));
916 puts (_("\tt\tchange a partition's filesystem id"));
917 puts (_("\tu\tchange units (cylinders/sectors)"));
918 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000919#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000920 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000921#endif
922}
923
924#if !defined (__alpha__)
925static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000926hidden(int type)
927{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000928 return type ^ 0x10;
929}
930
931static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000932is_bsd_partition_type(int type)
933{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000934 return (type == FREEBSD_PARTITION ||
935 type == hidden(FREEBSD_PARTITION) ||
936 type == NETBSD_PARTITION ||
937 type == hidden(NETBSD_PARTITION));
938}
939#endif
940
941static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000942bselect(void)
943{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000944#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000945 int t, ss;
946 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000947
Rob Landleyb73451d2006-02-24 16:29:00 +0000948 for (t = 0; t < 4; t++) {
949 p = get_part_table(t);
950 if (p && is_bsd_partition_type(p->sys_ind)) {
951 xbsd_part = p;
952 xbsd_part_index = t;
953 ss = get_start_sect(xbsd_part);
954 if (ss == 0) {
955 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
956 partname(disk_device, t+1, 0));
957 return;
958 }
959 printf(_("Reading disklabel of %s at sector %d.\n"),
960 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
961 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
962 if (xbsd_create_disklabel() == 0)
963 return;
964 break;
965 }
966 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000967
Rob Landleyb73451d2006-02-24 16:29:00 +0000968 if (t == 4) {
969 printf(_("There is no *BSD partition on %s.\n"), disk_device);
970 return;
971 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000972
973#elif defined (__alpha__)
974
Rob Landleyb73451d2006-02-24 16:29:00 +0000975 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
976 if (xbsd_create_disklabel() == 0)
977 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000978
979#endif
980
Rob Landleyb73451d2006-02-24 16:29:00 +0000981 while (1) {
982 putchar('\n');
983 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
984 case 'd':
985 xbsd_delete_part();
986 break;
987 case 'e':
988 xbsd_edit_disklabel();
989 break;
990 case 'i':
991 xbsd_write_bootstrap();
992 break;
993 case 'l':
994 xbsd_list_types();
995 break;
996 case 'n':
997 xbsd_new_part();
998 break;
999 case 'p':
1000 xbsd_print_disklabel(0);
1001 break;
1002 case 'q':
1003 close(fd);
1004 exit(EXIT_SUCCESS);
1005 case 'r':
1006 return;
1007 case 's':
1008 xbsd_print_disklabel(1);
1009 break;
1010 case 't':
1011 xbsd_change_fstype();
1012 break;
1013 case 'u':
1014 change_units();
1015 break;
1016 case 'w':
1017 xbsd_write_disklabel();
1018 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001019#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001020 case 'x':
1021 xbsd_link_part();
1022 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001023#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001024 default:
1025 bmenu();
1026 break;
1027 }
1028 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001029}
1030
1031static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001032xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001033{
Rob Landleyb73451d2006-02-24 16:29:00 +00001034 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001035
Rob Landleyb73451d2006-02-24 16:29:00 +00001036 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1037 xbsd_dlabel.d_partitions[i].p_size = 0;
1038 xbsd_dlabel.d_partitions[i].p_offset = 0;
1039 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1040 if (xbsd_dlabel.d_npartitions == i + 1)
1041 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1042 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001043}
1044
1045static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001046xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001047{
Rob Landleyb73451d2006-02-24 16:29:00 +00001048 off_t begin, end;
1049 char mesg[256];
1050 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001051
Rob Landleyb73451d2006-02-24 16:29:00 +00001052 if (!xbsd_check_new_partition(&i))
1053 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001054
1055#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001056 begin = get_start_sect(xbsd_part);
1057 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001058#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001059 begin = 0;
1060 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001061#endif
1062
Rob Landleyb73451d2006-02-24 16:29:00 +00001063 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1064 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1065 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001066
Rob Landleyb73451d2006-02-24 16:29:00 +00001067 if (display_in_cyl_units)
1068 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001069
Rob Landleyb73451d2006-02-24 16:29:00 +00001070 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1071 str_units(SINGULAR));
1072 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1073 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001074
Rob Landleyb73451d2006-02-24 16:29:00 +00001075 if (display_in_cyl_units)
1076 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001077
Rob Landleyb73451d2006-02-24 16:29:00 +00001078 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1079 xbsd_dlabel.d_partitions[i].p_offset = begin;
1080 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001081}
1082
1083static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001084xbsd_print_disklabel(int show_all)
1085{
1086 struct xbsd_disklabel *lp = &xbsd_dlabel;
1087 struct xbsd_partition *pp;
1088 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001089
Rob Landleyb73451d2006-02-24 16:29:00 +00001090 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001091#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001092 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001093#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001094 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001095#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001096 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1097 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1098 else
1099 printf(_("type: %d\n"), lp->d_type);
1100 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1101 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1102 printf(_("flags:"));
1103 if (lp->d_flags & BSD_D_REMOVABLE)
1104 printf(_(" removable"));
1105 if (lp->d_flags & BSD_D_ECC)
1106 printf(_(" ecc"));
1107 if (lp->d_flags & BSD_D_BADSECT)
1108 printf(_(" badsect"));
1109 printf("\n");
1110 /* On various machines the fields of *lp are short/int/long */
1111 /* In order to avoid problems, we cast them all to long. */
1112 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1113 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1114 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1115 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1116 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1117 printf(_("rpm: %d\n"), lp->d_rpm);
1118 printf(_("interleave: %d\n"), lp->d_interleave);
1119 printf(_("trackskew: %d\n"), lp->d_trackskew);
1120 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1121 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1122 (long) lp->d_headswitch);
1123 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1124 (long) lp->d_trkseek);
1125 printf(_("drivedata: "));
1126 for (i = NDDATA - 1; i >= 0; i--)
1127 if (lp->d_drivedata[i])
1128 break;
1129 if (i < 0)
1130 i = 0;
1131 for (j = 0; j <= i; j++)
1132 printf("%ld ", (long) lp->d_drivedata[j]);
1133 }
1134 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1135 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1136 pp = lp->d_partitions;
1137 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1138 if (pp->p_size) {
1139 if (display_in_cyl_units && lp->d_secpercyl) {
1140 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1141 'a' + i,
1142 (long) pp->p_offset / lp->d_secpercyl + 1,
1143 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1144 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1145 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1146 (long) pp->p_size / lp->d_secpercyl,
1147 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1148 );
1149 } else {
1150 printf(" %c: %8ld %8ld %8ld ",
1151 'a' + i,
1152 (long) pp->p_offset,
1153 (long) pp->p_offset + pp->p_size - 1,
1154 (long) pp->p_size
1155 );
1156 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001157
Rob Landleyb73451d2006-02-24 16:29:00 +00001158 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1159 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1160 else
1161 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001162
Rob Landleyb73451d2006-02-24 16:29:00 +00001163 switch (pp->p_fstype) {
1164 case BSD_FS_UNUSED:
1165 printf(" %5ld %5ld %5.5s ",
1166 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1167 break;
1168 case BSD_FS_BSDFFS:
1169 printf(" %5ld %5ld %5d ",
1170 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1171 break;
1172 default:
1173 printf("%22.22s", "");
1174 break;
1175 }
1176 printf("\n");
1177 }
1178 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001179}
1180
1181static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001182xbsd_write_disklabel(void)
1183{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001184#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001185 printf(_("Writing disklabel to %s.\n"), disk_device);
1186 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001187#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001188 printf(_("Writing disklabel to %s.\n"),
1189 partname(disk_device, xbsd_part_index + 1, 0));
1190 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001191#endif
1192 reread_partition_table(0); /* no exit yet */
1193}
1194
1195static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001196xbsd_create_disklabel(void)
1197{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001198 char c;
1199
1200#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001201 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001202#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001203 fprintf(stderr, _("%s contains no disklabel.\n"),
1204 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001205#endif
1206
1207 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001208 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001209 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001210 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001211#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001212 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001213 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001214#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001215 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001216#endif
1217 ) == 1) {
1218 xbsd_print_disklabel (1);
1219 return 1;
1220 } else
1221 return 0;
1222 } else if (c == 'n')
1223 return 0;
1224 }
1225}
1226
1227static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001228edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001229{
Rob Landleyb73451d2006-02-24 16:29:00 +00001230 do {
1231 fputs(mesg, stdout);
1232 printf(" (%d): ", def);
1233 if (!read_line())
1234 return def;
1235 }
1236 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1237 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001238}
1239
1240static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001241xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001242{
Rob Landleyb73451d2006-02-24 16:29:00 +00001243 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001244
Rob Landleyb73451d2006-02-24 16:29:00 +00001245 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001246
1247#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001248 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1249 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1250 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1251 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001252#endif
1253
Rob Landleyb73451d2006-02-24 16:29:00 +00001254 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1255 while (1) {
1256 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1257 _("sectors/cylinder"));
1258 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1259 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001260
Rob Landleyb73451d2006-02-24 16:29:00 +00001261 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1262 }
1263 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1264 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1265 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1266 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1267 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1268 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001269
Rob Landleyb73451d2006-02-24 16:29:00 +00001270 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001271}
1272
1273static int
1274xbsd_get_bootstrap (char *path, void *ptr, int size)
1275{
Rob Landleyb73451d2006-02-24 16:29:00 +00001276 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001277
Rob Landleyb73451d2006-02-24 16:29:00 +00001278 if ((fdb = open (path, O_RDONLY)) < 0) {
1279 perror(path);
1280 return 0;
1281 }
1282 if (read(fdb, ptr, size) < 0) {
1283 perror(path);
1284 close(fdb);
1285 return 0;
1286 }
1287 printf(" ... %s\n", path);
1288 close(fdb);
1289 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001290}
1291
1292static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001293sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001294{
Rob Landleyb73451d2006-02-24 16:29:00 +00001295 printf(_("\nSyncing disks.\n"));
1296 sync();
1297 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001298}
1299
1300static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001301xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001302{
Rob Landleyb73451d2006-02-24 16:29:00 +00001303 char *bootdir = BSD_LINUX_BOOTDIR;
1304 char path[MAXPATHLEN];
1305 char *dkbasename;
1306 struct xbsd_disklabel dl;
1307 char *d, *p, *e;
1308 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001309
Rob Landleyb73451d2006-02-24 16:29:00 +00001310 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1311 dkbasename = "sd";
1312 else
1313 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001314
Rob Landleyb73451d2006-02-24 16:29:00 +00001315 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1316 dkbasename, dkbasename, dkbasename);
1317 if (read_line()) {
1318 line_ptr[strlen(line_ptr)-1] = '\0';
1319 dkbasename = line_ptr;
1320 }
1321 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1322 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1323 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001324
Rob Landleyb73451d2006-02-24 16:29:00 +00001325/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1326 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
Mike Frysinger1a540302006-04-16 05:58:21 +00001327 memmove(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001328
Rob Landleyb73451d2006-02-24 16:29:00 +00001329/* The disklabel will be overwritten by 0's from bootxx anyway */
1330 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001331
Rob Landleyb73451d2006-02-24 16:29:00 +00001332 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1333 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001334 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001335 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001336
Rob Landleyb73451d2006-02-24 16:29:00 +00001337 e = d + sizeof(struct xbsd_disklabel);
1338 for (p = d; p < e; p++)
1339 if (*p) {
1340 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1341 exit(EXIT_FAILURE);
1342 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001343
Mike Frysinger1a540302006-04-16 05:58:21 +00001344 memmove(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001345
1346#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001347 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001348#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001349 sector = 0;
1350 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001351#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001352 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001353#endif
1354
Rob Landleyb73451d2006-02-24 16:29:00 +00001355 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1356 fdisk_fatal(unable_to_seek);
1357 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1358 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001359
1360#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001361 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001362#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001363 printf(_("Bootstrap installed on %s.\n"),
1364 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001365#endif
1366
Rob Landleyb73451d2006-02-24 16:29:00 +00001367 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001368}
1369
1370static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001371xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001372{
Rob Landleyb73451d2006-02-24 16:29:00 +00001373 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001374
Rob Landleyb73451d2006-02-24 16:29:00 +00001375 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1376 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001377}
1378
1379static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001380xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001381{
Rob Landleyb73451d2006-02-24 16:29:00 +00001382 char prompt[256];
1383 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001384
Rob Landleyb73451d2006-02-24 16:29:00 +00001385 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1386 do
1387 l = tolower(read_char(prompt));
1388 while (l < 'a' || l > 'a' + max - 1);
1389 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001390}
1391
1392static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001393xbsd_check_new_partition(int *i)
1394{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001395 /* room for more? various BSD flavours have different maxima */
1396 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1397 int t;
1398
1399 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1400 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1401 break;
1402
1403 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001404 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001405 "has been created\n"));
1406 return 0;
1407 }
1408 }
1409
1410 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1411
1412 if (*i >= xbsd_dlabel.d_npartitions)
1413 xbsd_dlabel.d_npartitions = (*i) + 1;
1414
1415 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001416 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001417 return 0;
1418 }
1419
1420 return 1;
1421}
1422
1423static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001424xbsd_list_types(void)
1425{
1426 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001427}
1428
1429static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001430xbsd_dkcksum(struct xbsd_disklabel *lp)
1431{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001432 u_short *start, *end;
1433 u_short sum = 0;
1434
1435 start = (u_short *) lp;
1436 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1437 while (start < end)
1438 sum ^= *start++;
1439 return sum;
1440}
1441
1442static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001443xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1444{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001445 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001446
Rob Landleyb73451d2006-02-24 16:29:00 +00001447 get_geometry();
1448 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001449
Rob Landleyb73451d2006-02-24 16:29:00 +00001450 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001451
Rob Landleyb73451d2006-02-24 16:29:00 +00001452 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1453 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001454 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001455 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001456
1457#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001458 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001459#endif
1460
1461#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001462 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001463#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001464 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001465#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001466 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1467 d->d_nsectors = sectors; /* sectors/track */
1468 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1469 d->d_ncylinders = cylinders;
1470 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1471 if (d->d_secpercyl == 0)
1472 d->d_secpercyl = 1; /* avoid segfaults */
1473 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001474
Rob Landleyb73451d2006-02-24 16:29:00 +00001475 d->d_rpm = 3600;
1476 d->d_interleave = 1;
1477 d->d_trackskew = 0;
1478 d->d_cylskew = 0;
1479 d->d_headswitch = 0;
1480 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001481
Rob Landleyb73451d2006-02-24 16:29:00 +00001482 d->d_magic2 = BSD_DISKMAGIC;
1483 d->d_bbsize = BSD_BBSIZE;
1484 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001485
1486#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001487 d->d_npartitions = 4;
1488 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001489 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001490 pp->p_offset = get_start_sect(p);
1491 pp->p_size = get_nr_sects(p);
1492 pp->p_fstype = BSD_FS_UNUSED;
1493 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001494 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001495 pp->p_offset = 0;
1496 pp->p_size = d->d_secperunit;
1497 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001498#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001499 d->d_npartitions = 3;
1500 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001501 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001502 pp->p_offset = 0;
1503 pp->p_size = d->d_secperunit;
1504 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001505#endif
1506
1507 return 1;
1508}
1509
1510/*
1511 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1512 * If it has the right magic, return 1.
1513 */
1514static int
1515xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1516{
1517 int t, sector;
1518
1519 /* p is used only to get the starting sector */
1520#if !defined (__alpha__)
1521 sector = (p ? get_start_sect(p) : 0);
1522#elif defined (__alpha__)
1523 sector = 0;
1524#endif
1525
Rob Landleyb73451d2006-02-24 16:29:00 +00001526 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1527 fdisk_fatal(unable_to_seek);
1528 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1529 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001530
Mike Frysinger1a540302006-04-16 05:58:21 +00001531 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1532 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001533
Rob Landleyb73451d2006-02-24 16:29:00 +00001534 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001535 return 0;
1536
Rob Landleyb73451d2006-02-24 16:29:00 +00001537 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1538 d->d_partitions[t].p_size = 0;
1539 d->d_partitions[t].p_offset = 0;
1540 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001541 }
1542
Rob Landleyb73451d2006-02-24 16:29:00 +00001543 if (d->d_npartitions > BSD_MAXPARTITIONS)
1544 fprintf(stderr, _("Warning: too many partitions "
1545 "(%d, maximum is %d).\n"),
1546 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001547 return 1;
1548}
1549
1550static int
1551xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1552{
Rob Landleyb73451d2006-02-24 16:29:00 +00001553 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001554
1555#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001556 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001557#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001558 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001559#endif
1560
Rob Landleyb73451d2006-02-24 16:29:00 +00001561 d->d_checksum = 0;
1562 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001563
Rob Landleyb73451d2006-02-24 16:29:00 +00001564 /* This is necessary if we want to write the bootstrap later,
1565 otherwise we'd write the old disklabel with the bootstrap.
1566 */
Mike Frysinger1a540302006-04-16 05:58:21 +00001567 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1568 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001569
1570#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001571 alpha_bootblock_checksum (disklabelbuffer);
1572 if (lseek(fd, 0, SEEK_SET) == -1)
1573 fdisk_fatal(unable_to_seek);
1574 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1575 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001576#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001577 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1578 fdisk_fatal(unable_to_seek);
1579 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1580 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001581#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001582 sync_disks();
1583 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001584}
1585
1586
1587#if !defined (__alpha__)
1588static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001589xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001590{
Rob Landleyb73451d2006-02-24 16:29:00 +00001591 switch (linux_type) {
1592 case 0x01: /* DOS 12-bit FAT */
1593 case 0x04: /* DOS 16-bit <32M */
1594 case 0x06: /* DOS 16-bit >=32M */
1595 case 0xe1: /* DOS access */
1596 case 0xe3: /* DOS R/O */
1597 case 0xf2: /* DOS secondary */
1598 return BSD_FS_MSDOS;
1599 case 0x07: /* OS/2 HPFS */
1600 return BSD_FS_HPFS;
1601 default:
1602 return BSD_FS_OTHER;
1603 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001604}
1605
1606static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001607xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001608{
Rob Landleyb73451d2006-02-24 16:29:00 +00001609 int k, i;
1610 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001611
Rob Landleyb73451d2006-02-24 16:29:00 +00001612 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001613
Rob Landleyb73451d2006-02-24 16:29:00 +00001614 if (!xbsd_check_new_partition(&i))
1615 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001616
Rob Landleyb73451d2006-02-24 16:29:00 +00001617 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001618
Rob Landleyb73451d2006-02-24 16:29:00 +00001619 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1620 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1621 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001622}
1623#endif
1624
1625#if defined (__alpha__)
1626
1627#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001628typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001629#endif
1630
1631static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001632alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001633{
Rob Landleyb73451d2006-02-24 16:29:00 +00001634 uint64_t *dp, sum;
1635 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001636
Rob Landleyb73451d2006-02-24 16:29:00 +00001637 dp = (uint64_t *)boot;
1638 sum = 0;
1639 for (i = 0; i < 63; i++)
1640 sum += dp[i];
1641 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001642}
1643#endif /* __alpha__ */
1644
1645#endif /* OSF_LABEL */
1646
1647#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1648static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001649__swap16(unsigned short x)
1650{
Eric Andersenacd244a2002-12-11 03:49:33 +00001651 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001652}
1653
Eric Andersenacd244a2002-12-11 03:49:33 +00001654static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001655__swap32(uint32_t x)
1656{
1657 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001658 ((x & 0xFF00) << 8) |
1659 ((x & 0xFF0000) >> 8) |
1660 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001661}
1662#endif
1663
1664#ifdef CONFIG_FEATURE_SGI_LABEL
1665/*
1666 *
1667 * fdisksgilabel.c
1668 *
1669 * Copyright (C) Andreas Neuper, Sep 1998.
1670 * This file may be modified and redistributed under
1671 * the terms of the GNU Public License.
1672 *
1673 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1674 * Internationalization
1675 */
1676
1677
Rob Landleyb73451d2006-02-24 16:29:00 +00001678static int sgi_other_endian;
1679static int debug;
1680static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001681
1682/*
1683 * only dealing with free blocks here
1684 */
1685
Rob Landleyb73451d2006-02-24 16:29:00 +00001686typedef struct {
1687 unsigned int first;
1688 unsigned int last;
1689} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001690static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1691
1692static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001693setfreelist(int i, unsigned int f, unsigned int l)
1694{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001695 freelist[i].first = f;
1696 freelist[i].last = l;
1697}
1698
1699static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001700add2freelist(unsigned int f, unsigned int l)
1701{
1702 int i;
1703 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001704 if (freelist[i].last == 0)
1705 break;
1706 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001707}
1708
1709static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001710clearfreelist(void)
1711{
Eric Andersen040f4402003-07-30 08:40:37 +00001712 int i;
1713
1714 for (i = 0; i < 17 ; i++)
1715 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001716}
1717
Eric Andersen040f4402003-07-30 08:40:37 +00001718static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001719isinfreelist(unsigned int b)
1720{
Eric Andersen040f4402003-07-30 08:40:37 +00001721 int i;
1722
1723 for (i = 0; i < 17 ; i++)
1724 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001725 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001726 return 0;
1727}
1728 /* return last vacant block of this stride (never 0). */
1729 /* the '>=' is not quite correct, but simplifies the code */
1730/*
1731 * end of free blocks section
1732 */
1733
1734static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001735/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1736/* 0x01 */ { "\x01" "SGI trkrepl" },
1737/* 0x02 */ { "\x02" "SGI secrepl" },
1738/* SGI_SWAP */ { "\x03" "SGI raw" },
1739/* 0x04 */ { "\x04" "SGI bsd" },
1740/* 0x05 */ { "\x05" "SGI sysv" },
1741/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1742/* SGI_EFS */ { "\x07" "SGI efs" },
1743/* 0x08 */ { "\x08" "SGI lvol" },
1744/* 0x09 */ { "\x09" "SGI rlvol" },
1745/* SGI_XFS */ { "\x0a" "SGI xfs" },
1746/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1747/* SGI_XLV */ { "\x0c" "SGI xlv" },
1748/* SGI_XVM */ { "\x0d" "SGI xvm" },
1749/* LINUX_SWAP */ { "\x82" "Linux swap" },
1750/* LINUX_NATIVE */ { "\x83" "Linux native" },
1751/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1752/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1753 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001754};
1755
1756
1757static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001758sgi_get_nsect(void)
1759{
1760 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001761}
1762
1763static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001764sgi_get_ntrks(void)
1765{
1766 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001767}
1768
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001769static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001770two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1771{
1772 int i = 0;
1773 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001774
Rob Landleyb73451d2006-02-24 16:29:00 +00001775 size /= sizeof(unsigned int);
1776 for (i = 0; i < size; i++)
1777 sum -= SGI_SSWAP32(base[i]);
1778 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001779}
1780
1781static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001782check_sgi_label(void)
1783{
1784 if (sizeof(sgilabel) > 512) {
1785 fprintf(stderr,
1786 _("According to MIPS Computer Systems, Inc the "
1787 "Label must not contain more than 512 bytes\n"));
1788 exit(1);
1789 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001790
Rob Landleyb73451d2006-02-24 16:29:00 +00001791 if (sgilabel->magic != SGI_LABEL_MAGIC
1792 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001793 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001794 return 0;
1795 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001796
Rob Landleyb73451d2006-02-24 16:29:00 +00001797 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1798 /*
1799 * test for correct checksum
1800 */
1801 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1802 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001803 fprintf(stderr,
1804 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001805 }
1806 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001807 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001808 partitions = 16;
1809 sgi_volumes = 15;
1810 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001811}
1812
Eric Andersen040f4402003-07-30 08:40:37 +00001813static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001814sgi_get_start_sector(int i)
1815{
1816 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001817}
1818
Eric Andersen040f4402003-07-30 08:40:37 +00001819static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001820sgi_get_num_sectors(int i)
1821{
1822 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001823}
1824
1825static int
Eric Andersen040f4402003-07-30 08:40:37 +00001826sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001827{
Rob Landleyb73451d2006-02-24 16:29:00 +00001828 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001829}
1830
1831static int
1832sgi_get_bootpartition(void)
1833{
Rob Landleyb73451d2006-02-24 16:29:00 +00001834 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001835}
1836
1837static int
1838sgi_get_swappartition(void)
1839{
Rob Landleyb73451d2006-02-24 16:29:00 +00001840 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001841}
1842
1843static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001844sgi_list_table(int xtra)
1845{
1846 int i, w, wd;
1847 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001848
Rob Landleyb73451d2006-02-24 16:29:00 +00001849 if(xtra) {
1850 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1851 "%d cylinders, %d physical cylinders\n"
1852 "%d extra sects/cyl, interleave %d:1\n"
1853 "%s\n"
1854 "Units = %s of %d * 512 bytes\n\n"),
1855 disk_device, heads, sectors, cylinders,
1856 SGI_SSWAP16(sgiparam.pcylcount),
1857 SGI_SSWAP16(sgiparam.sparecyl),
1858 SGI_SSWAP16(sgiparam.ilfact),
1859 (char *)sgilabel,
1860 str_units(PLURAL), units_per_sector);
1861 } else {
1862 printf( _("\nDisk %s (SGI disk label): "
1863 "%d heads, %d sectors, %d cylinders\n"
1864 "Units = %s of %d * 512 bytes\n\n"),
1865 disk_device, heads, sectors, cylinders,
1866 str_units(PLURAL), units_per_sector );
1867 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001868
Rob Landleyb73451d2006-02-24 16:29:00 +00001869 w = strlen(disk_device);
1870 wd = strlen(_("Device"));
1871 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001872 w = wd;
1873
Rob Landleyb73451d2006-02-24 16:29:00 +00001874 printf(_("----- partitions -----\n"
1875 "Pt# %*s Info Start End Sectors Id System\n"),
1876 w + 2, _("Device"));
1877 for (i = 0 ; i < partitions; i++) {
1878 if( sgi_get_num_sectors(i) || debug ) {
1879 uint32_t start = sgi_get_start_sector(i);
1880 uint32_t len = sgi_get_num_sectors(i);
1881 kpi++; /* only count nonempty partitions */
1882 printf(
1883 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1884/* fdisk part number */ i+1,
1885/* device */ partname(disk_device, kpi, w+3),
1886/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1887/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1888/* start */ (long) scround(start),
1889/* end */ (long) scround(start+len)-1,
1890/* no odd flag on end */(long) len,
1891/* type id */ sgi_get_sysid(i),
1892/* type name */ partition_type(sgi_get_sysid(i)));
1893 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001894 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001895 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1896 "----- Directory Entries -----\n"),
1897 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001898 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001899 if (sgilabel->directory[i].vol_file_size) {
1900 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1901 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1902 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001903
Rob Landleyb73451d2006-02-24 16:29:00 +00001904 printf(_("%2d: %-10s sector%5u size%8u\n"),
1905 i, (char*)name, (unsigned int) start, (unsigned int) len);
1906 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001907 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001908}
1909
1910static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001911sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001912{
Rob Landleyb73451d2006-02-24 16:29:00 +00001913 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001914}
1915
Eric Andersen040f4402003-07-30 08:40:37 +00001916static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001917sgi_get_lastblock(void)
1918{
1919 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001920}
1921
1922static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001923sgi_set_swappartition(int i)
1924{
1925 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001926}
1927
1928static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001929sgi_check_bootfile(const char* aFile)
1930{
1931 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1932 printf(_("\nInvalid Bootfile!\n"
1933 "\tThe bootfile must be an absolute non-zero pathname,\n"
1934 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1935 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001936 } else {
1937 if (strlen(aFile) > 16) {
1938 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001939 "16 bytes maximum.\n"));
1940 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001941 } else {
1942 if (aFile[0] != '/') {
1943 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001944 "fully qualified pathname.\n"));
1945 return 0;
1946 }
Eric Andersen040f4402003-07-30 08:40:37 +00001947 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001948 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001949 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001950 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1951 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001952 /* filename is correct and did change */
1953 return 1;
1954 }
1955 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001956}
1957
1958static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001959sgi_get_bootfile(void)
1960{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001961 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001962}
1963
1964static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001965sgi_set_bootfile(const char* aFile)
1966{
1967 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001968
Rob Landleyb73451d2006-02-24 16:29:00 +00001969 if (sgi_check_bootfile(aFile)) {
1970 while (i < 16) {
1971 if ((aFile[i] != '\n') /* in principle caught again by next line */
1972 && (strlen(aFile) > i))
1973 sgilabel->boot_file[i] = aFile[i];
1974 else
1975 sgilabel->boot_file[i] = 0;
1976 i++;
1977 }
1978 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001979 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001980}
1981
1982static void
1983create_sgiinfo(void)
1984{
Rob Landleyb73451d2006-02-24 16:29:00 +00001985 /* I keep SGI's habit to write the sgilabel to the second block */
1986 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1987 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1988 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001989}
1990
Eric Andersen040f4402003-07-30 08:40:37 +00001991static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001992
1993static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001994sgi_write_table(void)
1995{
1996 sgilabel->csum = 0;
1997 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1998 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1999 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00002000 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00002001
2002 if (lseek(fd, 0, SEEK_SET) < 0)
2003 fdisk_fatal(unable_to_seek);
2004 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
2005 fdisk_fatal(unable_to_write);
2006 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2007 /*
2008 * keep this habit of first writing the "sgilabel".
2009 * I never tested whether it works without (AN 981002).
2010 */
2011 sgiinfo *info = fill_sgiinfo();
2012 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2013 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2014 fdisk_fatal(unable_to_seek);
2015 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2016 fdisk_fatal(unable_to_write);
2017 free(info);
2018 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002019}
2020
2021static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002022compare_start(int *x, int *y)
2023{
2024 /*
2025 * sort according to start sectors
2026 * and prefers largest partition:
2027 * entry zero is entire disk entry
2028 */
2029 unsigned int i = *x;
2030 unsigned int j = *y;
2031 unsigned int a = sgi_get_start_sector(i);
2032 unsigned int b = sgi_get_start_sector(j);
2033 unsigned int c = sgi_get_num_sectors(i);
2034 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002035
Rob Landleyb73451d2006-02-24 16:29:00 +00002036 if (a == b)
2037 return (d > c) ? 1 : (d == c) ? 0 : -1;
2038 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002039}
2040
2041
2042static int
Eric Andersen040f4402003-07-30 08:40:37 +00002043verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002044{
Rob Landleyb73451d2006-02-24 16:29:00 +00002045 int Index[16]; /* list of valid partitions */
2046 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2047 int entire = 0, i = 0;
2048 unsigned int start = 0;
2049 long long gap = 0; /* count unused blocks */
2050 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002051
Rob Landleyb73451d2006-02-24 16:29:00 +00002052 clearfreelist();
2053 for (i = 0; i < 16; i++) {
2054 if (sgi_get_num_sectors(i) != 0) {
2055 Index[sortcount++] = i;
2056 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2057 if (entire++ == 1) {
2058 if (verbose)
2059 printf(_("More than one entire disk entry present.\n"));
2060 }
2061 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002062 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002063 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002064 if (sortcount == 0) {
2065 if (verbose)
2066 printf(_("No partitions defined\n"));
2067 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2068 }
2069 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2070 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2071 if ((Index[0] != 10) && verbose)
2072 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2073 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2074 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002075 "at block 0,\n"
2076 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002077 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002078 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002079 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2080 printf(_("The entire disk partition is only %d diskblock large,\n"
2081 "but the disk is %d diskblocks long.\n"),
2082 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002083 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002084 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002085 if (verbose)
2086 printf(_("One Partition (#11) should cover the entire disk.\n"));
2087 if (debug > 2)
2088 printf("sysid=%d\tpartition=%d\n",
2089 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002090 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002091 for (i = 1, start = 0; i < sortcount; i++) {
2092 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2093
2094 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2095 if (debug) /* I do not understand how some disks fulfil it */
2096 if (verbose)
2097 printf(_("Partition %d does not start on cylinder boundary.\n"),
2098 Index[i]+1);
2099 }
2100 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2101 if (debug) /* I do not understand how some disks fulfil it */
2102 if (verbose)
2103 printf(_("Partition %d does not end on cylinder boundary.\n"),
2104 Index[i]+1);
2105 }
2106 /* We cannot handle several "entire disk" entries. */
2107 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2108 if (start > sgi_get_start_sector(Index[i])) {
2109 if (verbose)
2110 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2111 Index[i-1]+1, Index[i]+1,
2112 start - sgi_get_start_sector(Index[i]));
2113 if (gap > 0) gap = -gap;
2114 if (gap == 0) gap = -1;
2115 }
2116 if (start < sgi_get_start_sector(Index[i])) {
2117 if (verbose)
2118 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2119 sgi_get_start_sector(Index[i]) - start,
2120 start, sgi_get_start_sector(Index[i])-1);
2121 gap += sgi_get_start_sector(Index[i]) - start;
2122 add2freelist(start, sgi_get_start_sector(Index[i]));
2123 }
2124 start = sgi_get_start_sector(Index[i])
2125 + sgi_get_num_sectors(Index[i]);
2126 if (debug > 1) {
2127 if (verbose)
2128 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2129 sgi_get_start_sector(Index[i]),
2130 sgi_get_num_sectors(Index[i]),
2131 sgi_get_sysid(Index[i]));
2132 }
2133 }
2134 if (start < lastblock) {
2135 if (verbose)
2136 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2137 lastblock - start, start, lastblock-1);
2138 gap += lastblock - start;
2139 add2freelist(start, lastblock);
2140 }
2141 /*
2142 * Done with arithmetics
2143 * Go for details now
2144 */
2145 if (verbose) {
2146 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2147 printf(_("\nThe boot partition does not exist.\n"));
2148 }
2149 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2150 printf(_("\nThe swap partition does not exist.\n"));
2151 } else {
2152 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2153 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2154 printf(_("\nThe swap partition has no swap type.\n"));
2155 }
2156 if (sgi_check_bootfile("/unix"))
2157 printf(_("\tYou have chosen an unusual boot file name.\n"));
2158 }
2159 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002160}
2161
2162static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002163sgi_gaps(void)
2164{
2165 /*
2166 * returned value is:
2167 * = 0 : disk is properly filled to the rim
2168 * < 0 : there is an overlap
2169 * > 0 : there is still some vacant space
2170 */
2171 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002172}
2173
2174static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002175sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002176{
Rob Landleyb73451d2006-02-24 16:29:00 +00002177 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2178 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2179 return;
2180 }
2181 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2182 && (sgi_get_start_sector(i) < 1) ) {
2183 read_chars(
2184 _("It is highly recommended that the partition at offset 0\n"
2185 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2186 "retrieve from its directory standalone tools like sash and fx.\n"
2187 "Only the \"SGI volume\" entire disk section may violate this.\n"
2188 "Type YES if you are sure about tagging this partition differently.\n"));
2189 if (strcmp(line_ptr, _("YES\n")))
2190 return;
2191 }
2192 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002193}
2194
2195/* returns partition index of first entry marked as entire disk */
2196static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002197sgi_entire(void)
2198{
2199 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002200
Rob Landleyb73451d2006-02-24 16:29:00 +00002201 for (i = 0; i < 16; i++)
2202 if (sgi_get_sysid(i) == SGI_VOLUME)
2203 return i;
2204 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002205}
2206
2207static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002208sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2209{
2210 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2211 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2212 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2213 set_changed(i);
2214 if (sgi_gaps() < 0) /* rebuild freelist */
2215 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002216}
2217
2218static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002219sgi_set_entire(void)
2220{
2221 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002222
Rob Landleyb73451d2006-02-24 16:29:00 +00002223 for (n = 10; n < partitions; n++) {
2224 if(!sgi_get_num_sectors(n) ) {
2225 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2226 break;
2227 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002228 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002229}
2230
2231static void
2232sgi_set_volhdr(void)
2233{
Rob Landleyb73451d2006-02-24 16:29:00 +00002234 int n;
2235
2236 for (n = 8; n < partitions; n++) {
2237 if (!sgi_get_num_sectors(n)) {
2238 /*
2239 * 5 cylinders is an arbitrary value I like
2240 * IRIX 5.3 stored files in the volume header
2241 * (like sash, symmon, fx, ide) with ca. 3200
2242 * sectors.
2243 */
2244 if (heads * sectors * 5 < sgi_get_lastblock())
2245 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2246 break;
2247 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002248 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002249}
2250
2251static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002252sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002253{
Rob Landleyb73451d2006-02-24 16:29:00 +00002254 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002255}
2256
2257static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002258sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002259{
Rob Landleyb73451d2006-02-24 16:29:00 +00002260 char mesg[256];
2261 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002262
Rob Landleyb73451d2006-02-24 16:29:00 +00002263 if (n == 10) {
2264 sys = SGI_VOLUME;
2265 } else if (n == 8) {
2266 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002267 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002268 if(sgi_get_num_sectors(n)) {
2269 printf(_("Partition %d is already defined. Delete "
2270 "it before re-adding it.\n"), n + 1);
2271 return;
2272 }
2273 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2274 printf(_("Attempting to generate entire disk entry automatically.\n"));
2275 sgi_set_entire();
2276 sgi_set_volhdr();
2277 }
2278 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2279 printf(_("The entire disk is already covered with partitions.\n"));
2280 return;
2281 }
2282 if (sgi_gaps() < 0) {
2283 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2284 return;
2285 }
2286 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2287 while (1) {
2288 if(sys == SGI_VOLUME) {
2289 last = sgi_get_lastblock();
2290 first = read_int(0, 0, last-1, 0, mesg);
2291 if (first != 0) {
2292 printf(_("It is highly recommended that eleventh partition\n"
2293 "covers the entire disk and is of type `SGI volume'\n"));
2294 }
2295 } else {
2296 first = freelist[0].first;
2297 last = freelist[0].last;
2298 first = read_int(scround(first), scround(first), scround(last)-1,
2299 0, mesg);
2300 }
2301 if (display_in_cyl_units)
2302 first *= units_per_sector;
2303 else
2304 first = first; /* align to cylinder if you know how ... */
2305 if(!last )
2306 last = isinfreelist(first);
2307 if(last == 0) {
2308 printf(_("You will get a partition overlap on the disk. "
2309 "Fix it first!\n"));
2310 } else
2311 break;
2312 }
2313 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2314 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2315 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002316 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002317 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002318 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002319 last = last; /* align to cylinder if You know how ... */
2320 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2321 printf(_("It is highly recommended that eleventh partition\n"
2322 "covers the entire disk and is of type `SGI volume'\n"));
2323 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002324}
2325
Eric Andersen040f4402003-07-30 08:40:37 +00002326#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002327static void
2328create_sgilabel(void)
2329{
Rob Landleyb73451d2006-02-24 16:29:00 +00002330 struct hd_geometry geometry;
2331 struct {
2332 unsigned int start;
2333 unsigned int nsect;
2334 int sysid;
2335 } old[4];
2336 int i = 0;
2337 long longsectors; /* the number of sectors on the device */
2338 int res; /* the result from the ioctl */
2339 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002340
Rob Landleyb73451d2006-02-24 16:29:00 +00002341 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002342
Rob Landleyb73451d2006-02-24 16:29:00 +00002343 fprintf( stderr,
2344 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2345 "until you decide to write them. After that, of course, the previous\n"
2346 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002347
Rob Landley2c39eee2006-05-05 16:54:40 +00002348 sgi_other_endian = (BB_LITTLE_ENDIAN);
Rob Landleyb73451d2006-02-24 16:29:00 +00002349 res = ioctl(fd, BLKGETSIZE, &longsectors);
2350 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2351 heads = geometry.heads;
2352 sectors = geometry.sectors;
2353 if (res == 0) {
2354 /* the get device size ioctl was successful */
2355 cylinders = longsectors / (heads * sectors);
2356 cylinders /= sec_fac;
2357 } else {
2358 /* otherwise print error and use truncated version */
2359 cylinders = geometry.cylinders;
2360 fprintf(stderr,
2361 _("Warning: BLKGETSIZE ioctl failed on %s. "
2362 "Using geometry cylinder value of %d.\n"
2363 "This value may be truncated for devices"
2364 " > 33.8 GB.\n"), disk_device, cylinders);
2365 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002366 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002367 for (i = 0; i < 4; i++) {
2368 old[i].sysid = 0;
2369 if (valid_part_table_flag(MBRbuffer)) {
2370 if(get_part_table(i)->sys_ind) {
2371 old[i].sysid = get_part_table(i)->sys_ind;
2372 old[i].start = get_start_sect(get_part_table(i));
2373 old[i].nsect = get_nr_sects(get_part_table(i));
2374 printf(_("Trying to keep parameters of partition %d.\n"), i);
2375 if (debug)
2376 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2377 old[i].sysid, old[i].start, old[i].nsect);
2378 }
2379 }
2380 }
Eric Andersen040f4402003-07-30 08:40:37 +00002381
Rob Landleyb73451d2006-02-24 16:29:00 +00002382 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2383 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2384 sgilabel->boot_part = SGI_SSWAP16(0);
2385 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002386
Rob Landleyb73451d2006-02-24 16:29:00 +00002387 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2388 memset(sgilabel->boot_file, 0, 16);
2389 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002390
Rob Landleyb73451d2006-02-24 16:29:00 +00002391 sgilabel->devparam.skew = (0);
2392 sgilabel->devparam.gap1 = (0);
2393 sgilabel->devparam.gap2 = (0);
2394 sgilabel->devparam.sparecyl = (0);
2395 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2396 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2397 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002398 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002399 sgilabel->devparam.cmd_tag_queue_depth = (0);
2400 sgilabel->devparam.unused0 = (0);
2401 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2402 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002403 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002404 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2405 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2406 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002407 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002408 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2409 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2410 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2411 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2412 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2413 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2414 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2415 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2416 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2417 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2418 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002419 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002420 partitions = 16;
2421 sgi_volumes = 15;
2422 sgi_set_entire();
2423 sgi_set_volhdr();
2424 for (i = 0; i < 4; i++) {
2425 if(old[i].sysid) {
2426 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2427 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002428 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002429}
2430
2431static void
2432sgi_set_xcyl(void)
2433{
Rob Landleyb73451d2006-02-24 16:29:00 +00002434 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002435}
Eric Andersen040f4402003-07-30 08:40:37 +00002436#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002437
2438/* _____________________________________________________________
2439 */
2440
Eric Andersen040f4402003-07-30 08:40:37 +00002441static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002442fill_sgiinfo(void)
2443{
Rob Landleyb73451d2006-02-24 16:29:00 +00002444 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002445
Rob Landleyb73451d2006-02-24 16:29:00 +00002446 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2447 info->b1 = SGI_SSWAP32(-1);
2448 info->b2 = SGI_SSWAP16(-1);
2449 info->b3 = SGI_SSWAP16(1);
2450 /* You may want to replace this string !!!!!!! */
2451 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2452 strcpy( (char*)info->serial, "0000" );
2453 info->check1816 = SGI_SSWAP16(18*256 +16 );
2454 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2455 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002456}
2457#endif /* SGI_LABEL */
2458
2459
2460#ifdef CONFIG_FEATURE_SUN_LABEL
2461/*
2462 * fdisksunlabel.c
2463 *
2464 * I think this is mostly, or entirely, due to
2465 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2466 *
2467 * Merged with fdisk for other architectures, aeb, June 1998.
2468 *
2469 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2470 * Internationalization
2471 */
2472
2473
Rob Landleyb73451d2006-02-24 16:29:00 +00002474static int sun_other_endian;
2475static int scsi_disk;
2476static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002477
2478#ifndef IDE0_MAJOR
2479#define IDE0_MAJOR 3
2480#endif
2481#ifndef IDE1_MAJOR
2482#define IDE1_MAJOR 22
2483#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002484
Rob Landleyb73451d2006-02-24 16:29:00 +00002485static void
2486guess_device_type(void)
2487{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002488 struct stat bootstat;
2489
Rob Landleyb73451d2006-02-24 16:29:00 +00002490 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002491 scsi_disk = 0;
2492 floppy = 0;
2493 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002494 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2495 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002496 scsi_disk = 0;
2497 floppy = 0;
2498 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002499 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002500 scsi_disk = 0;
2501 floppy = 1;
2502 } else {
2503 scsi_disk = 1;
2504 floppy = 0;
2505 }
2506}
2507
2508static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002509 { "\x00" "Empty" }, /* 0 */
2510 { "\x01" "Boot" }, /* 1 */
2511 { "\x02" "SunOS root" }, /* 2 */
2512 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2513 { "\x04" "SunOS usr" }, /* 4 */
2514 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2515 { "\x06" "SunOS stand" }, /* 6 */
2516 { "\x07" "SunOS var" }, /* 7 */
2517 { "\x08" "SunOS home" }, /* 8 */
2518 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2519 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2520 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002521/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002522 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2523 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002524};
2525
2526
2527static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002528set_sun_partition(int i, uint start, uint stop, int sysid)
2529{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002530 sunlabel->infos[i].id = sysid;
2531 sunlabel->partitions[i].start_cylinder =
2532 SUN_SSWAP32(start / (heads * sectors));
2533 sunlabel->partitions[i].num_sectors =
2534 SUN_SSWAP32(stop - start);
2535 set_changed(i);
2536}
2537
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002538static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002539check_sun_label(void)
2540{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002541 unsigned short *ush;
2542 int csum;
2543
Rob Landleyb73451d2006-02-24 16:29:00 +00002544 if (sunlabel->magic != SUN_LABEL_MAGIC
2545 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002546 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002547 sun_other_endian = 0;
2548 return 0;
2549 }
2550 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2551 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2552 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2553 if (csum) {
2554 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2555 "Probably you'll have to set all the values,\n"
2556 "e.g. heads, sectors, cylinders and partitions\n"
2557 "or force a fresh label (s command in main menu)\n"));
2558 } else {
2559 heads = SUN_SSWAP16(sunlabel->ntrks);
2560 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2561 sectors = SUN_SSWAP16(sunlabel->nsect);
2562 }
2563 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002564 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002565 partitions = 8;
2566 return 1;
2567}
2568
2569static const struct sun_predefined_drives {
2570 const char *vendor;
2571 const char *model;
2572 unsigned short sparecyl;
2573 unsigned short ncyl;
2574 unsigned short nacyl;
2575 unsigned short pcylcount;
2576 unsigned short ntrks;
2577 unsigned short nsect;
2578 unsigned short rspeed;
2579} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002580 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2581 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2582 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2583 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2584 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2585 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2586 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2587 { "","SUN0104",1,974,2,1019,6,35,3662},
2588 { "","SUN0207",4,1254,2,1272,9,36,3600},
2589 { "","SUN0327",3,1545,2,1549,9,46,3600},
2590 { "","SUN0340",0,1538,2,1544,6,72,4200},
2591 { "","SUN0424",2,1151,2,2500,9,80,4400},
2592 { "","SUN0535",0,1866,2,2500,7,80,5400},
2593 { "","SUN0669",5,1614,2,1632,15,54,3600},
2594 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2595 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2596 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2597 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2598 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002599};
2600
2601static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002602sun_autoconfigure_scsi(void)
2603{
2604 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002605
2606#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002607 unsigned int id[2];
2608 char buffer[2048];
2609 char buffer2[2048];
2610 FILE *pfd;
2611 char *vendor;
2612 char *model;
2613 char *q;
2614 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002615
Rob Landleyb73451d2006-02-24 16:29:00 +00002616 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2617 sprintf(buffer,
2618 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002619#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002620 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002621#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002622 /* This is very wrong (works only if you have one HBA),
2623 but I haven't found a way how to get hostno
2624 from the current kernel */
2625 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002626#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002627 (id[0]>>16) & 0xff,
2628 id[0] & 0xff,
2629 (id[0]>>8) & 0xff
2630 );
2631 pfd = fopen("/proc/scsi/scsi","r");
2632 if (pfd) {
2633 while (fgets(buffer2, 2048, pfd)) {
2634 if (!strcmp(buffer, buffer2)) {
2635 if (fgets(buffer2,2048,pfd)) {
2636 q = strstr(buffer2,"Vendor: ");
2637 if (q) {
2638 q += 8;
2639 vendor = q;
2640 q = strstr(q," ");
2641 *q++ = 0; /* truncate vendor name */
2642 q = strstr(q,"Model: ");
2643 if (q) {
2644 *q = 0;
2645 q += 7;
2646 model = q;
2647 q = strstr(q," Rev: ");
2648 if (q) {
2649 *q = 0;
2650 for (i = 0; i < SIZE(sun_drives); i++) {
2651 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2652 continue;
2653 if (!strstr(model, sun_drives[i].model))
2654 continue;
2655 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2656 p = sun_drives + i;
2657 break;
2658 }
2659 }
2660 }
2661 }
2662 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002663 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002664 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002665 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002666 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002667 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002668 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002669#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002670 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002671}
2672
Rob Landleyb73451d2006-02-24 16:29:00 +00002673static void
2674create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002675{
2676 struct hd_geometry geometry;
2677 unsigned int ndiv;
2678 int i;
2679 unsigned char c;
2680 const struct sun_predefined_drives *p = NULL;
2681
2682 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002683 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2684 "until you decide to write them. After that, of course, the previous\n"
2685 "content won't be recoverable.\n\n"));
Rob Landley2c39eee2006-05-05 16:54:40 +00002686 sun_other_endian = BB_LITTLE_ENDIAN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002687 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2688 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2689 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002690 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002691 " ? auto configure\n"
2692 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002693 for (i = 0; i < SIZE(sun_drives); i++) {
2694 printf(" %c %s%s%s\n",
2695 i + 'a', sun_drives[i].vendor,
2696 (*sun_drives[i].vendor) ? " " : "",
2697 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002698 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002699 while (1) {
2700 c = read_char(_("Select type (? for auto, 0 for custom): "));
2701 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2702 p = sun_drives + c - 'a';
2703 break;
2704 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2705 p = sun_drives + c - 'A';
2706 break;
2707 } else if (c == '0') {
2708 break;
2709 } else if (c == '?' && scsi_disk) {
2710 p = sun_autoconfigure_scsi();
2711 if (!p)
2712 printf(_("Autoconfigure failed.\n"));
2713 else
2714 break;
2715 }
2716 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002717 }
2718 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002719 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2720 heads = geometry.heads;
2721 sectors = geometry.sectors;
2722 cylinders = geometry.cylinders;
2723 } else {
2724 heads = 0;
2725 sectors = 0;
2726 cylinders = 0;
2727 }
2728 if (floppy) {
2729 sunlabel->nacyl = 0;
2730 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2731 sunlabel->rspeed = SUN_SSWAP16(300);
2732 sunlabel->ilfact = SUN_SSWAP16(1);
2733 sunlabel->sparecyl = 0;
2734 } else {
2735 heads = read_int(1,heads,1024,0,_("Heads"));
2736 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002737 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002738 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002739 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002740 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2741 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2742 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2743 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2744 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2745 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2746 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002747 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002748 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2749 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2750 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2751 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2752 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2753 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2754 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2755 sunlabel->ilfact = SUN_SSWAP16(1);
2756 cylinders = p->ncyl;
2757 heads = p->ntrks;
2758 sectors = p->nsect;
2759 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002760 }
2761
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002762 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002763 "%s%s%s cyl %d alt %d hd %d sec %d",
2764 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2765 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002766 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2767
2768 sunlabel->ntrks = SUN_SSWAP16(heads);
2769 sunlabel->nsect = SUN_SSWAP16(sectors);
2770 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2771 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002772 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002773 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002774 if (cylinders * heads * sectors >= 150 * 2048) {
2775 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2776 } else
2777 ndiv = cylinders * 2 / 3;
2778 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2779 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2780 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002781 }
2782 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2783 {
2784 unsigned short *ush = (unsigned short *)sunlabel;
2785 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002786 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002787 csum ^= *ush++;
2788 sunlabel->csum = csum;
2789 }
2790
2791 set_all_unchanged();
2792 set_changed(0);
2793 get_boot(create_empty_sun);
2794}
2795
2796static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002797toggle_sunflags(int i, unsigned char mask)
2798{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002799 if (sunlabel->infos[i].flags & mask)
2800 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002801 else
2802 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002803 set_changed(i);
2804}
2805
2806static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002807fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2808{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002809 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002810
2811 *start = 0;
2812 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002813 for (i = 0; i < partitions; i++) {
2814 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002815 && sunlabel->infos[i].id
2816 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002817 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2818 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2819 if (continuous) {
2820 if (starts[i] == *start)
2821 *start += lens[i];
2822 else if (starts[i] + lens[i] >= *stop)
2823 *stop = starts[i];
2824 else
2825 continuous = 0;
2826 /* There will be probably more gaps
2827 than one, so lets check afterwards */
2828 }
2829 } else {
2830 starts[i] = 0;
2831 lens[i] = 0;
2832 }
2833 }
2834}
2835
2836static uint *verify_sun_starts;
2837
2838static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002839verify_sun_cmp(int *a, int *b)
2840{
2841 if (*a == -1) return 1;
2842 if (*b == -1) return -1;
2843 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2844 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002845}
2846
2847static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002848verify_sun(void)
2849{
2850 uint starts[8], lens[8], start, stop;
2851 int i,j,k,starto,endo;
2852 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002853
Rob Landleyb73451d2006-02-24 16:29:00 +00002854 verify_sun_starts = starts;
2855 fetch_sun(starts,lens,&start,&stop);
2856 for (k = 0; k < 7; k++) {
2857 for (i = 0; i < 8; i++) {
2858 if (k && (lens[i] % (heads * sectors))) {
2859 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002860 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002861 if (lens[i]) {
2862 for (j = 0; j < i; j++)
2863 if (lens[j]) {
2864 if (starts[j] == starts[i]+lens[i]) {
2865 starts[j] = starts[i]; lens[j] += lens[i];
2866 lens[i] = 0;
2867 } else if (starts[i] == starts[j]+lens[j]){
2868 lens[j] += lens[i];
2869 lens[i] = 0;
2870 } else if (!k) {
2871 if (starts[i] < starts[j]+lens[j]
2872 && starts[j] < starts[i]+lens[i]) {
2873 starto = starts[i];
2874 if (starts[j] > starto)
2875 starto = starts[j];
2876 endo = starts[i]+lens[i];
2877 if (starts[j]+lens[j] < endo)
2878 endo = starts[j]+lens[j];
2879 printf(_("Partition %d overlaps with others in "
2880 "sectors %d-%d\n"), i+1, starto, endo);
2881 }
2882 }
2883 }
2884 }
2885 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002886 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002887 for (i = 0; i < 8; i++) {
2888 if (lens[i])
2889 array[i] = i;
2890 else
2891 array[i] = -1;
2892 }
2893 qsort(array,SIZE(array),sizeof(array[0]),
2894 (int (*)(const void *,const void *)) verify_sun_cmp);
2895 if (array[0] == -1) {
2896 printf(_("No partitions defined\n"));
2897 return;
2898 }
2899 stop = cylinders * heads * sectors;
2900 if (starts[array[0]])
2901 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2902 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2903 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2904 }
2905 start = starts[array[i]] + lens[array[i]];
2906 if (start < stop)
2907 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002908}
2909
2910static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002911add_sun_partition(int n, int sys)
2912{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002913 uint start, stop, stop2;
2914 uint starts[8], lens[8];
2915 int whole_disk = 0;
2916
2917 char mesg[256];
2918 int i, first, last;
2919
2920 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2921 printf(_("Partition %d is already defined. Delete "
2922 "it before re-adding it.\n"), n + 1);
2923 return;
2924 }
2925
2926 fetch_sun(starts,lens,&start,&stop);
2927 if (stop <= start) {
2928 if (n == 2)
2929 whole_disk = 1;
2930 else {
2931 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002932 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002933 return;
2934 }
2935 }
2936 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002937 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002938 if (whole_disk)
2939 first = read_int(0, 0, 0, 0, mesg);
2940 else
2941 first = read_int(scround(start), scround(stop)+1,
2942 scround(stop), 0, mesg);
2943 if (display_in_cyl_units)
2944 first *= units_per_sector;
2945 else
2946 /* Starting sector has to be properly aligned */
2947 first = (first + heads * sectors - 1) / (heads * sectors);
2948 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002949 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002950It is highly recommended that the third partition covers the whole disk\n\
2951and is of type `Whole disk'\n");
2952 /* ewt asks to add: "don't start a partition at cyl 0"
2953 However, edmundo@rano.demon.co.uk writes:
2954 "In addition to having a Sun partition table, to be able to
2955 boot from the disc, the first partition, /dev/sdX1, must
2956 start at cylinder 0. This means that /dev/sdX1 contains
2957 the partition table and the boot block, as these are the
2958 first two sectors of the disc. Therefore you must be
2959 careful what you use /dev/sdX1 for. In particular, you must
2960 not use a partition starting at cylinder 0 for Linux swap,
2961 as that would overwrite the partition table and the boot
2962 block. You may, however, use such a partition for a UFS
2963 or EXT2 file system, as these file systems leave the first
2964 1024 bytes undisturbed. */
2965 /* On the other hand, one should not use partitions
2966 starting at block 0 in an md, or the label will
2967 be trashed. */
2968 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002969 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002970 break;
2971 if (i < partitions && !whole_disk) {
2972 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002973 whole_disk = 1;
2974 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002975 }
2976 printf(_("Sector %d is already allocated\n"), first);
2977 } else
2978 break;
2979 }
2980 stop = cylinders * heads * sectors;
2981 stop2 = stop;
2982 for (i = 0; i < partitions; i++) {
2983 if (starts[i] > first && starts[i] < stop)
2984 stop = starts[i];
2985 }
2986 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002987 _("Last %s or +size or +sizeM or +sizeK"),
2988 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002989 if (whole_disk)
2990 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2991 0, mesg);
2992 else if (n == 2 && !first)
2993 last = read_int(scround(first), scround(stop2), scround(stop2),
2994 scround(first), mesg);
2995 else
2996 last = read_int(scround(first), scround(stop), scround(stop),
2997 scround(first), mesg);
2998 if (display_in_cyl_units)
2999 last *= units_per_sector;
3000 if (n == 2 && !first) {
3001 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003002 whole_disk = 1;
3003 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003004 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003005 printf(_("You haven't covered the whole disk with "
3006 "the 3rd partition, but your value\n"
3007 "%d %s covers some other partition. "
3008 "Your entry has been changed\n"
3009 "to %d %s\n"),
3010 scround(last), str_units(SINGULAR),
3011 scround(stop), str_units(SINGULAR));
3012 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003013 }
3014 } else if (!whole_disk && last > stop)
3015 last = stop;
3016
Rob Landleyb73451d2006-02-24 16:29:00 +00003017 if (whole_disk)
3018 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003019 set_sun_partition(n, first, last, sys);
3020}
3021
3022static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003023sun_delete_partition(int i)
3024{
Eric Andersen040f4402003-07-30 08:40:37 +00003025 unsigned int nsec;
3026
Rob Landleyb73451d2006-02-24 16:29:00 +00003027 if (i == 2
3028 && sunlabel->infos[i].id == WHOLE_DISK
3029 && !sunlabel->partitions[i].start_cylinder
3030 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003031 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003032 "consider leaving this\n"
3033 "partition as Whole disk (5), starting at 0, with %u "
3034 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003035 sunlabel->infos[i].id = 0;
3036 sunlabel->partitions[i].num_sectors = 0;
3037}
3038
3039static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003040sun_change_sysid(int i, int sys)
3041{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003042 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003043 read_chars(
3044 _("It is highly recommended that the partition at offset 0\n"
3045 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3046 "there may destroy your partition table and bootblock.\n"
3047 "Type YES if you're very sure you would like that partition\n"
3048 "tagged with 82 (Linux swap): "));
3049 if (strcmp (line_ptr, _("YES\n")))
3050 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003051 }
3052 switch (sys) {
3053 case SUNOS_SWAP:
3054 case LINUX_SWAP:
3055 /* swaps are not mountable by default */
3056 sunlabel->infos[i].flags |= 0x01;
3057 break;
3058 default:
3059 /* assume other types are mountable;
3060 user can change it anyway */
3061 sunlabel->infos[i].flags &= ~0x01;
3062 break;
3063 }
3064 sunlabel->infos[i].id = sys;
3065}
3066
3067static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003068sun_list_table(int xtra)
3069{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003070 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003071
3072 w = strlen(disk_device);
3073 if (xtra)
3074 printf(
3075 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3076 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3077 "%d extra sects/cyl, interleave %d:1\n"
3078 "%s\n"
3079 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003080 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3081 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3082 SUN_SSWAP16(sunlabel->pcylcount),
3083 SUN_SSWAP16(sunlabel->sparecyl),
3084 SUN_SSWAP16(sunlabel->ilfact),
3085 (char *)sunlabel,
3086 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003087 else
3088 printf(
3089 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3090 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003091 disk_device, heads, sectors, cylinders,
3092 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003093
3094 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003095 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003096 for (i = 0 ; i < partitions; i++) {
3097 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003098 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3099 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003100 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3101 partname(disk_device, i+1, w), /* device */
3102 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3103 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3104 (long) scround(start), /* start */
3105 (long) scround(start+len), /* end */
3106 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3107 sunlabel->infos[i].id, /* type id */
3108 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003109 }
3110 }
3111}
3112
Eric Andersen040f4402003-07-30 08:40:37 +00003113#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3114
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003115static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003116sun_set_alt_cyl(void)
3117{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003118 sunlabel->nacyl =
3119 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003120 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003121}
3122
3123static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003124sun_set_ncyl(int cyl)
3125{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003126 sunlabel->ncyl = SUN_SSWAP16(cyl);
3127}
3128
3129static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003130sun_set_xcyl(void)
3131{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003132 sunlabel->sparecyl =
3133 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003134 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003135}
3136
3137static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003138sun_set_ilfact(void)
3139{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003140 sunlabel->ilfact =
3141 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003142 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003143}
3144
3145static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003146sun_set_rspeed(void)
3147{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003148 sunlabel->rspeed =
3149 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003150 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003151}
3152
3153static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003154sun_set_pcylcount(void)
3155{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003156 sunlabel->pcylcount =
3157 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003158 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003159}
Eric Andersen040f4402003-07-30 08:40:37 +00003160#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003161
3162static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003163sun_write_table(void)
3164{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003165 unsigned short *ush = (unsigned short *)sunlabel;
3166 unsigned short csum = 0;
3167
Rob Landleyb73451d2006-02-24 16:29:00 +00003168 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003169 csum ^= *ush++;
3170 sunlabel->csum = csum;
3171 if (lseek(fd, 0, SEEK_SET) < 0)
3172 fdisk_fatal(unable_to_seek);
3173 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3174 fdisk_fatal(unable_to_write);
3175}
3176#endif /* SUN_LABEL */
3177
3178/* DOS partition types */
3179
3180static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003181 { "\x00" "Empty" },
3182 { "\x01" "FAT12" },
3183 { "\x04" "FAT16 <32M" },
3184 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3185 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3186 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3187 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3188 { "\x0b" "Win95 FAT32" },
3189 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3190 { "\x0e" "Win95 FAT16 (LBA)" },
3191 { "\x0f" "Win95 Ext'd (LBA)" },
3192 { "\x11" "Hidden FAT12" },
3193 { "\x12" "Compaq diagnostics" },
3194 { "\x14" "Hidden FAT16 <32M" },
3195 { "\x16" "Hidden FAT16" },
3196 { "\x17" "Hidden HPFS/NTFS" },
3197 { "\x1b" "Hidden Win95 FAT32" },
3198 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3199 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3200 { "\x3c" "PartitionMagic recovery" },
3201 { "\x41" "PPC PReP Boot" },
3202 { "\x42" "SFS" },
3203 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3204 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3205 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3206 { "\x82" "Linux swap" }, /* also Solaris */
3207 { "\x83" "Linux" },
3208 { "\x84" "OS/2 hidden C: drive" },
3209 { "\x85" "Linux extended" },
3210 { "\x86" "NTFS volume set" },
3211 { "\x87" "NTFS volume set" },
3212 { "\x8e" "Linux LVM" },
3213 { "\x9f" "BSD/OS" }, /* BSDI */
3214 { "\xa0" "IBM Thinkpad hibernation" },
3215 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3216 { "\xa6" "OpenBSD" },
3217 { "\xa8" "Darwin UFS" },
3218 { "\xa9" "NetBSD" },
3219 { "\xab" "Darwin boot" },
3220 { "\xb7" "BSDI fs" },
3221 { "\xb8" "BSDI swap" },
3222 { "\xbe" "Solaris boot" },
3223 { "\xeb" "BeOS fs" },
3224 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3225 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3226 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3227 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3228 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3229 autodetect using persistent
3230 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003231#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003232 { "\x02" "XENIX root" },
3233 { "\x03" "XENIX usr" },
3234 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3235 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3236 { "\x10" "OPUS" },
3237 { "\x18" "AST SmartSleep" },
3238 { "\x24" "NEC DOS" },
3239 { "\x39" "Plan 9" },
3240 { "\x40" "Venix 80286" },
3241 { "\x4d" "QNX4.x" },
3242 { "\x4e" "QNX4.x 2nd part" },
3243 { "\x4f" "QNX4.x 3rd part" },
3244 { "\x50" "OnTrack DM" },
3245 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3246 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3247 { "\x53" "OnTrack DM6 Aux3" },
3248 { "\x54" "OnTrackDM6" },
3249 { "\x55" "EZ-Drive" },
3250 { "\x56" "Golden Bow" },
3251 { "\x5c" "Priam Edisk" },
3252 { "\x61" "SpeedStor" },
3253 { "\x64" "Novell Netware 286" },
3254 { "\x65" "Novell Netware 386" },
3255 { "\x70" "DiskSecure Multi-Boot" },
3256 { "\x75" "PC/IX" },
3257 { "\x93" "Amoeba" },
3258 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3259 { "\xa7" "NeXTSTEP" },
3260 { "\xbb" "Boot Wizard hidden" },
3261 { "\xc1" "DRDOS/sec (FAT-12)" },
3262 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3263 { "\xc6" "DRDOS/sec (FAT-16)" },
3264 { "\xc7" "Syrinx" },
3265 { "\xda" "Non-FS data" },
3266 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003267 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003268 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3269 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3270 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003271 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003272 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3273 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003274 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003275 { "\xf1" "SpeedStor" },
3276 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3277 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3278 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003279#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003280 { 0 }
3281};
3282
3283
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003284
3285/* A valid partition table sector ends in 0x55 0xaa */
3286static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003287part_table_flag(const char *b)
3288{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003289 return ((uint) b[510]) + (((uint) b[511]) << 8);
3290}
3291
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003292
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003293#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003294static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003295write_part_table_flag(char *b)
3296{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003297 b[510] = 0x55;
3298 b[511] = 0xaa;
3299}
3300
3301/* start_sect and nr_sects are stored little endian on all machines */
3302/* moreover, they are not aligned correctly */
3303static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003304store4_little_endian(unsigned char *cp, unsigned int val)
3305{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003306 cp[0] = (val & 0xff);
3307 cp[1] = ((val >> 8) & 0xff);
3308 cp[2] = ((val >> 16) & 0xff);
3309 cp[3] = ((val >> 24) & 0xff);
3310}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003311#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003312
3313static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003314read4_little_endian(const unsigned char *cp)
3315{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003316 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3317 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3318}
3319
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003320#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003321static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003322set_start_sect(struct partition *p, unsigned int start_sect)
3323{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003324 store4_little_endian(p->start4, start_sect);
3325}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003326#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003327
Eric Andersend9261492004-06-28 23:50:31 +00003328static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003329get_start_sect(const struct partition *p)
3330{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003331 return read4_little_endian(p->start4);
3332}
3333
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003334#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003335static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003336set_nr_sects(struct partition *p, int32_t nr_sects)
3337{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003338 store4_little_endian(p->size4, nr_sects);
3339}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003340#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003341
Eric Andersend9261492004-06-28 23:50:31 +00003342static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003343get_nr_sects(const struct partition *p)
3344{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003345 return read4_little_endian(p->size4);
3346}
3347
3348/* normally O_RDWR, -l option gives O_RDONLY */
3349static int type_open = O_RDWR;
3350
3351
Rob Landleyb73451d2006-02-24 16:29:00 +00003352static int ext_index; /* the prime extended partition */
3353static int listing; /* no aborts for fdisk -l */
3354static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003355#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3356static int dos_changed;
3357static int nowarn; /* no warnings for fdisk -l/-s */
3358#endif
3359
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003360
3361
Rob Landleyb73451d2006-02-24 16:29:00 +00003362static uint user_cylinders, user_heads, user_sectors;
3363static uint pt_heads, pt_sectors;
3364static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003365
Eric Andersend9261492004-06-28 23:50:31 +00003366static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003367
Eric Andersen040f4402003-07-30 08:40:37 +00003368static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003369
3370
3371static jmp_buf listingbuf;
3372
Rob Landleyb73451d2006-02-24 16:29:00 +00003373static void fdisk_fatal(enum failure why)
3374{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003375 const char *message;
3376
3377 if (listing) {
3378 close(fd);
3379 longjmp(listingbuf, 1);
3380 }
3381
3382 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003383 case unable_to_open:
3384 message = "Unable to open %s\n";
3385 break;
3386 case unable_to_read:
3387 message = "Unable to read %s\n";
3388 break;
3389 case unable_to_seek:
3390 message = "Unable to seek on %s\n";
3391 break;
3392 case unable_to_write:
3393 message = "Unable to write %s\n";
3394 break;
3395 case ioctl_error:
3396 message = "BLKGETSIZE ioctl failed on %s\n";
3397 break;
3398 default:
3399 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003400 }
3401
3402 fputc('\n', stderr);
3403 fprintf(stderr, message, disk_device);
3404 exit(1);
3405}
3406
3407static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003408seek_sector(off_t secno)
3409{
Eric Andersen0a92f352004-03-30 09:21:54 +00003410 off_t offset = secno * sector_size;
3411 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003412 fdisk_fatal(unable_to_seek);
3413}
3414
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003415#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003416static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003417write_sector(off_t secno, char *buf)
3418{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003419 seek_sector(secno);
3420 if (write(fd, buf, sector_size) != sector_size)
3421 fdisk_fatal(unable_to_write);
3422}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003423#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003424
3425/* Allocate a buffer and read a partition table sector */
3426static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003427read_pte(struct pte *pe, off_t offset)
3428{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003429 pe->offset = offset;
3430 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003431 seek_sector(offset);
3432 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3433 fdisk_fatal(unable_to_read);
3434#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003435 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003436#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003437 pe->part_table = pe->ext_pointer = NULL;
3438}
3439
3440static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003441get_partition_start(const struct pte *pe)
3442{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003443 return pe->offset + get_start_sect(pe->part_table);
3444}
3445
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003446#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003447/*
3448 * Avoid warning about DOS partitions when no DOS partition was changed.
3449 * Here a heuristic "is probably dos partition".
3450 * We might also do the opposite and warn in all cases except
3451 * for "is probably nondos partition".
3452 */
3453static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003454is_dos_partition(int t)
3455{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003456 return (t == 1 || t == 4 || t == 6 ||
3457 t == 0x0b || t == 0x0c || t == 0x0e ||
3458 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3459 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3460 t == 0xc1 || t == 0xc4 || t == 0xc6);
3461}
3462
3463static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003464menu(void)
3465{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003466#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003467 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003468 puts(_("Command action"));
3469 puts(_("\ta\ttoggle a read only flag")); /* sun */
3470 puts(_("\tb\tedit bsd disklabel"));
3471 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3472 puts(_("\td\tdelete a partition"));
3473 puts(_("\tl\tlist known partition types"));
3474 puts(_("\tm\tprint this menu"));
3475 puts(_("\tn\tadd a new partition"));
3476 puts(_("\to\tcreate a new empty DOS partition table"));
3477 puts(_("\tp\tprint the partition table"));
3478 puts(_("\tq\tquit without saving changes"));
3479 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3480 puts(_("\tt\tchange a partition's system id"));
3481 puts(_("\tu\tchange display/entry units"));
3482 puts(_("\tv\tverify the partition table"));
3483 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003484#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003485 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003486#endif
3487 } else
3488#endif
3489#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003490 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003491 puts(_("Command action"));
3492 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3493 puts(_("\tb\tedit bootfile entry")); /* sgi */
3494 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3495 puts(_("\td\tdelete a partition"));
3496 puts(_("\tl\tlist known partition types"));
3497 puts(_("\tm\tprint this menu"));
3498 puts(_("\tn\tadd a new partition"));
3499 puts(_("\to\tcreate a new empty DOS partition table"));
3500 puts(_("\tp\tprint the partition table"));
3501 puts(_("\tq\tquit without saving changes"));
3502 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3503 puts(_("\tt\tchange a partition's system id"));
3504 puts(_("\tu\tchange display/entry units"));
3505 puts(_("\tv\tverify the partition table"));
3506 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003507 } else
3508#endif
3509#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003510 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003511 puts(_("Command action"));
3512 puts(_("\tm\tprint this menu"));
3513 puts(_("\to\tcreate a new empty DOS partition table"));
3514 puts(_("\tq\tquit without saving changes"));
3515 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003516 } else
3517#endif
3518 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003519 puts(_("Command action"));
3520 puts(_("\ta\ttoggle a bootable flag"));
3521 puts(_("\tb\tedit bsd disklabel"));
3522 puts(_("\tc\ttoggle the dos compatibility flag"));
3523 puts(_("\td\tdelete a partition"));
3524 puts(_("\tl\tlist known partition types"));
3525 puts(_("\tm\tprint this menu"));
3526 puts(_("\tn\tadd a new partition"));
3527 puts(_("\to\tcreate a new empty DOS partition table"));
3528 puts(_("\tp\tprint the partition table"));
3529 puts(_("\tq\tquit without saving changes"));
3530 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3531 puts(_("\tt\tchange a partition's system id"));
3532 puts(_("\tu\tchange display/entry units"));
3533 puts(_("\tv\tverify the partition table"));
3534 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003535#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003536 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003537#endif
3538 }
3539}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003540#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3541
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003542
3543#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3544static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003545xmenu(void)
3546{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003547#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003548 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003549 puts(_("Command action"));
3550 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3551 puts(_("\tc\tchange number of cylinders"));
3552 puts(_("\td\tprint the raw data in the partition table"));
3553 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3554 puts(_("\th\tchange number of heads"));
3555 puts(_("\ti\tchange interleave factor")); /*sun*/
3556 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3557 puts(_("\tm\tprint this menu"));
3558 puts(_("\tp\tprint the partition table"));
3559 puts(_("\tq\tquit without saving changes"));
3560 puts(_("\tr\treturn to main menu"));
3561 puts(_("\ts\tchange number of sectors/track"));
3562 puts(_("\tv\tverify the partition table"));
3563 puts(_("\tw\twrite table to disk and exit"));
3564 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003565 } else
3566#endif
3567#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003568 if (label_sgi == 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#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003586 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003587 puts(_("Command action"));
3588 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3589 puts(_("\tc\tchange number of cylinders"));
3590 puts(_("\td\tprint the raw data in the partition table"));
3591 puts(_("\te\tlist extended partitions")); /* !sun */
3592 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3593 puts(_("\th\tchange number of heads"));
3594 puts(_("\tm\tprint this menu"));
3595 puts(_("\tp\tprint the partition table"));
3596 puts(_("\tq\tquit without saving changes"));
3597 puts(_("\tr\treturn to main menu"));
3598 puts(_("\ts\tchange number of sectors/track"));
3599 puts(_("\tv\tverify the partition table"));
3600 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003601 } else
3602#endif
3603 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003604 puts(_("Command action"));
3605 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3606 puts(_("\tc\tchange number of cylinders"));
3607 puts(_("\td\tprint the raw data in the partition table"));
3608 puts(_("\te\tlist extended partitions")); /* !sun */
3609 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003610#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003611 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003612#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003613 puts(_("\th\tchange number of heads"));
3614 puts(_("\tm\tprint this menu"));
3615 puts(_("\tp\tprint the partition table"));
3616 puts(_("\tq\tquit without saving changes"));
3617 puts(_("\tr\treturn to main menu"));
3618 puts(_("\ts\tchange number of sectors/track"));
3619 puts(_("\tv\tverify the partition table"));
3620 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003621 }
3622}
3623#endif /* ADVANCED mode */
3624
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003625#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003626static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003627get_sys_types(void)
3628{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003629 return (
3630#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003631 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003632#endif
3633#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003634 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003635#endif
3636 i386_sys_types);
3637}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003638#else
3639#define get_sys_types() i386_sys_types
3640#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003641
3642static const char *partition_type(unsigned char type)
3643{
3644 int i;
3645 const struct systypes *types = get_sys_types();
3646
Rob Landleyb73451d2006-02-24 16:29:00 +00003647 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003648 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003649 return types[i].name + 1;
3650
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003651 return _("Unknown");
3652}
3653
3654
3655#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3656static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003657get_sysid(int i)
3658{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003659 return (
3660#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003661 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003662#endif
3663#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003664 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003665#endif
3666 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003667}
3668
3669void list_types(const struct systypes *sys)
3670{
3671 uint last[4], done = 0, next = 0, size;
3672 int i;
3673
3674 for (i = 0; sys[i].name; i++);
3675 size = i;
3676
3677 for (i = 3; i >= 0; i--)
3678 last[3 - i] = done += (size + i - done) / (i + 1);
3679 i = done = 0;
3680
3681 do {
3682 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003683 (unsigned char)sys[next].name[0],
3684 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003685 next = last[i++] + done;
3686 if (i > 3 || next >= last[i]) {
3687 i = 0;
3688 next = ++done;
3689 }
3690 } while (done < last[0]);
3691 putchar('\n');
3692}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003693#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003694
3695static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003696is_cleared_partition(const struct partition *p)
3697{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003698 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3699 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3700 get_start_sect(p) || get_nr_sects(p));
3701}
3702
3703static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003704clear_partition(struct partition *p)
3705{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003706 if (!p)
3707 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003708 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003709}
3710
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003711#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003712static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003713set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3714{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003715 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003716 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003717
3718 if (doext) {
3719 p = ptes[i].ext_pointer;
3720 offset = extended_offset;
3721 } else {
3722 p = ptes[i].part_table;
3723 offset = ptes[i].offset;
3724 }
3725 p->boot_ind = 0;
3726 p->sys_ind = sysid;
3727 set_start_sect(p, start - offset);
3728 set_nr_sects(p, stop - start + 1);
3729 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3730 start = heads*sectors*1024 - 1;
3731 set_hsc(p->head, p->sector, p->cyl, start);
3732 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3733 stop = heads*sectors*1024 - 1;
3734 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3735 ptes[i].changed = 1;
3736}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003737#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003738
3739static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003740test_c(const char **m, const char *mesg)
3741{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003742 int val = 0;
3743 if (!*m)
3744 fprintf(stderr, _("You must set"));
3745 else {
3746 fprintf(stderr, " %s", *m);
3747 val = 1;
3748 }
3749 *m = mesg;
3750 return val;
3751}
3752
3753static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003754warn_geometry(void)
3755{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003756 const char *m = NULL;
3757 int prev = 0;
3758
3759 if (!heads)
3760 prev = test_c(&m, _("heads"));
3761 if (!sectors)
3762 prev = test_c(&m, _("sectors"));
3763 if (!cylinders)
3764 prev = test_c(&m, _("cylinders"));
3765 if (!m)
3766 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003767
3768 fprintf(stderr, "%s%s.\n"
3769#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3770 "You can do this from the extra functions menu.\n"
3771#endif
3772 , prev ? _(" and ") : " ", m);
3773
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003774 return 1;
3775}
3776
3777static void update_units(void)
3778{
3779 int cyl_units = heads * sectors;
3780
3781 if (display_in_cyl_units && cyl_units)
3782 units_per_sector = cyl_units;
3783 else
3784 units_per_sector = 1; /* in sectors */
3785}
3786
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003787#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003788static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003789warn_cylinders(void)
3790{
Rob Landley5527b912006-02-25 03:46:10 +00003791 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003792 fprintf(stderr, _("\n"
3793"The number of cylinders for this disk is set to %d.\n"
3794"There is nothing wrong with that, but this is larger than 1024,\n"
3795"and could in certain setups cause problems with:\n"
3796"1) software that runs at boot time (e.g., old versions of LILO)\n"
3797"2) booting and partitioning software from other OSs\n"
3798" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3799 cylinders);
3800}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003801#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003802
3803static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003804read_extended(int ext)
3805{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003806 int i;
3807 struct pte *pex;
3808 struct partition *p, *q;
3809
3810 ext_index = ext;
3811 pex = &ptes[ext];
3812 pex->ext_pointer = pex->part_table;
3813
3814 p = pex->part_table;
3815 if (!get_start_sect(p)) {
3816 fprintf(stderr,
3817 _("Bad offset in primary extended partition\n"));
3818 return;
3819 }
3820
Rob Landleyb73451d2006-02-24 16:29:00 +00003821 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003822 struct pte *pe = &ptes[partitions];
3823
3824 if (partitions >= MAXIMUM_PARTS) {
3825 /* This is not a Linux restriction, but
3826 this program uses arrays of size MAXIMUM_PARTS.
3827 Do not try to `improve' this test. */
3828 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003829#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003830 fprintf(stderr,
3831 _("Warning: deleting partitions after %d\n"),
3832 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003833 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003834#endif
3835 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003836 return;
3837 }
3838
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003839 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003840
3841 if (!extended_offset)
3842 extended_offset = get_start_sect(p);
3843
3844 q = p = pt_offset(pe->sectorbuffer, 0);
3845 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003846 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003847 if (pe->ext_pointer)
3848 fprintf(stderr,
3849 _("Warning: extra link "
3850 "pointer in partition table"
3851 " %d\n"), partitions + 1);
3852 else
3853 pe->ext_pointer = p;
3854 } else if (p->sys_ind) {
3855 if (pe->part_table)
3856 fprintf(stderr,
3857 _("Warning: ignoring extra "
3858 "data in partition table"
3859 " %d\n"), partitions + 1);
3860 else
3861 pe->part_table = p;
3862 }
3863 }
3864
3865 /* very strange code here... */
3866 if (!pe->part_table) {
3867 if (q != pe->ext_pointer)
3868 pe->part_table = q;
3869 else
3870 pe->part_table = q + 1;
3871 }
3872 if (!pe->ext_pointer) {
3873 if (q != pe->part_table)
3874 pe->ext_pointer = q;
3875 else
3876 pe->ext_pointer = q + 1;
3877 }
3878
3879 p = pe->ext_pointer;
3880 partitions++;
3881 }
3882
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003883#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003884 /* remove empty links */
3885 remove:
3886 for (i = 4; i < partitions; i++) {
3887 struct pte *pe = &ptes[i];
3888
3889 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003890 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003891 printf("omitting empty partition (%d)\n", i+1);
3892 delete_partition(i);
3893 goto remove; /* numbering changed */
3894 }
3895 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003896#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003897}
3898
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003899#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003900static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003901create_doslabel(void)
3902{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003903 int i;
3904
3905 fprintf(stderr,
3906 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3907 "until you decide to write them. After that, of course, the previous\n"
3908 "content won't be recoverable.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00003909
3910 current_label_type = label_dos;
3911
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003912#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003913 possibly_osf_label = 0;
3914#endif
3915 partitions = 4;
3916
3917 for (i = 510-64; i < 510; i++)
3918 MBRbuffer[i] = 0;
3919 write_part_table_flag(MBRbuffer);
3920 extended_offset = 0;
3921 set_all_unchanged();
3922 set_changed(0);
3923 get_boot(create_empty_dos);
3924}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003925#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003926
3927static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003928get_sectorsize(void)
3929{
Rob Landley736e5252006-02-25 03:36:00 +00003930 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003931 int arg;
3932 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3933 sector_size = arg;
3934 if (sector_size != DEFAULT_SECTOR_SIZE)
3935 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003936 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003937 }
3938}
3939
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003940static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003941get_kernel_geometry(void)
3942{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003943 struct hd_geometry geometry;
3944
3945 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3946 kern_heads = geometry.heads;
3947 kern_sectors = geometry.sectors;
3948 /* never use geometry.cylinders - it is truncated */
3949 }
3950}
3951
3952static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003953get_partition_table_geometry(void)
3954{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003955 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003956 struct partition *p;
3957 int i, h, s, hh, ss;
3958 int first = 1;
3959 int bad = 0;
3960
Eric Andersen3496fdc2006-01-30 23:09:20 +00003961 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003962 return;
3963
3964 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003965 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003966 p = pt_offset(bufp, i);
3967 if (p->sys_ind != 0) {
3968 h = p->end_head + 1;
3969 s = (p->end_sector & 077);
3970 if (first) {
3971 hh = h;
3972 ss = s;
3973 first = 0;
3974 } else if (hh != h || ss != s)
3975 bad = 1;
3976 }
3977 }
3978
3979 if (!first && !bad) {
3980 pt_heads = hh;
3981 pt_sectors = ss;
3982 }
3983}
3984
Rob Landleyb73451d2006-02-24 16:29:00 +00003985static void
3986get_geometry(void)
3987{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003988 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003989 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003990
3991 get_sectorsize();
3992 sec_fac = sector_size / 512;
3993#ifdef CONFIG_FEATURE_SUN_LABEL
3994 guess_device_type();
3995#endif
3996 heads = cylinders = sectors = 0;
3997 kern_heads = kern_sectors = 0;
3998 pt_heads = pt_sectors = 0;
3999
4000 get_kernel_geometry();
4001 get_partition_table_geometry();
4002
4003 heads = user_heads ? user_heads :
4004 pt_heads ? pt_heads :
4005 kern_heads ? kern_heads : 255;
4006 sectors = user_sectors ? user_sectors :
4007 pt_sectors ? pt_sectors :
4008 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004009 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4010 /* got bytes */
4011 } else {
4012 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004013
4014 if (ioctl(fd, BLKGETSIZE, &longsectors))
4015 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004016 bytes = ((unsigned long long) longsectors) << 9;
4017 }
4018
4019 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004020
4021 sector_offset = 1;
4022 if (dos_compatible_flag)
4023 sector_offset = sectors;
4024
Eric Andersen040f4402003-07-30 08:40:37 +00004025 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004026 if (!cylinders)
4027 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004028}
4029
4030/*
4031 * Read MBR. Returns:
4032 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4033 * 0: found or created label
4034 * 1: I/O error
4035 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004036static int
4037get_boot(enum action what)
4038{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004039 int i;
4040
4041 partitions = 4;
4042
4043 for (i = 0; i < 4; i++) {
4044 struct pte *pe = &ptes[i];
4045
4046 pe->part_table = pt_offset(MBRbuffer, i);
4047 pe->ext_pointer = NULL;
4048 pe->offset = 0;
4049 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004050#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004051 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004052#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004053 }
4054
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004055#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004056 if (what == create_empty_sun && check_sun_label())
4057 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004058#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004059
4060 memset(MBRbuffer, 0, 512);
4061
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004062#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004063 if (what == create_empty_dos)
4064 goto got_dos_table; /* skip reading disk */
4065
4066 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004067 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4068 if (what == try_only)
4069 return 1;
4070 fdisk_fatal(unable_to_open);
4071 } else
4072 printf(_("You will not be able to write "
4073 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004074 }
4075
4076 if (512 != read(fd, MBRbuffer, 512)) {
4077 if (what == try_only)
4078 return 1;
4079 fdisk_fatal(unable_to_read);
4080 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004081#else
4082 if ((fd = open(disk_device, O_RDONLY)) < 0)
4083 return 1;
4084 if (512 != read(fd, MBRbuffer, 512))
4085 return 1;
4086#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004087
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004088 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004089
4090 update_units();
4091
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004092#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004093 if (check_sun_label())
4094 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004095#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004096
4097#ifdef CONFIG_FEATURE_SGI_LABEL
4098 if (check_sgi_label())
4099 return 0;
4100#endif
4101
4102#ifdef CONFIG_FEATURE_AIX_LABEL
4103 if (check_aix_label())
4104 return 0;
4105#endif
4106
4107#ifdef CONFIG_FEATURE_OSF_LABEL
4108 if (check_osf_label()) {
4109 possibly_osf_label = 1;
4110 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004111 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004112 return 0;
4113 }
4114 printf(_("This disk has both DOS and BSD magic.\n"
4115 "Give the 'b' command to go to BSD mode.\n"));
4116 }
4117#endif
4118
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004119#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004120 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004121#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004122
4123 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004124#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4125 return -1;
4126#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004127 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004128 case fdisk:
4129 fprintf(stderr,
4130 _("Device contains neither a valid DOS "
4131 "partition table, nor Sun, SGI or OSF "
4132 "disklabel\n"));
4133#ifdef __sparc__
4134#ifdef CONFIG_FEATURE_SUN_LABEL
4135 create_sunlabel();
4136#endif
4137#else
4138 create_doslabel();
4139#endif
4140 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004141 case try_only:
4142 return -1;
4143 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004144#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004145 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004146#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004147 break;
4148 default:
4149 fprintf(stderr, _("Internal error\n"));
4150 exit(1);
4151 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004152#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004153 }
4154
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004155#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004156 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004157#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004158 warn_geometry();
4159
4160 for (i = 0; i < 4; i++) {
4161 struct pte *pe = &ptes[i];
4162
Rob Landleyb73451d2006-02-24 16:29:00 +00004163 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004164 if (partitions != 4)
4165 fprintf(stderr, _("Ignoring extra extended "
4166 "partition %d\n"), i + 1);
4167 else
4168 read_extended(i);
4169 }
4170 }
4171
4172 for (i = 3; i < partitions; i++) {
4173 struct pte *pe = &ptes[i];
4174
4175 if (!valid_part_table_flag(pe->sectorbuffer)) {
4176 fprintf(stderr,
4177 _("Warning: invalid flag 0x%04x of partition "
4178 "table %d will be corrected by w(rite)\n"),
4179 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004180#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004181 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004182#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004183 }
4184 }
4185
4186 return 0;
4187}
4188
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004189#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004190/*
4191 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4192 * If the user hits Enter, DFLT is returned.
4193 * Answers like +10 are interpreted as offsets from BASE.
4194 *
4195 * There is no default if DFLT is not between LOW and HIGH.
4196 */
4197static uint
4198read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4199{
4200 uint i;
4201 int default_ok = 1;
4202 static char *ms = NULL;
4203 static int mslen = 0;
4204
4205 if (!ms || strlen(mesg)+100 > mslen) {
4206 mslen = strlen(mesg)+200;
4207 ms = xrealloc(ms,mslen);
4208 }
4209
4210 if (dflt < low || dflt > high)
4211 default_ok = 0;
4212
4213 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004214 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004215 mesg, low, high, dflt);
4216 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004217 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004218
4219 while (1) {
4220 int use_default = default_ok;
4221
4222 /* ask question and read answer */
4223 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004224 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004225 continue;
4226
Eric Andersen84bdea82004-05-19 10:49:17 +00004227 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004228 int minus = (*line_ptr == '-');
4229 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004230
Rob Landleyb73451d2006-02-24 16:29:00 +00004231 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004232
Rob Landleyb73451d2006-02-24 16:29:00 +00004233 while (isdigit(*++line_ptr))
4234 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004235
Rob Landleyb73451d2006-02-24 16:29:00 +00004236 switch (*line_ptr) {
4237 case 'c':
4238 case 'C':
4239 if (!display_in_cyl_units)
4240 i *= heads * sectors;
4241 break;
4242 case 'K':
4243 absolute = 1024;
4244 break;
4245 case 'k':
4246 absolute = 1000;
4247 break;
4248 case 'm':
4249 case 'M':
4250 absolute = 1000000;
4251 break;
4252 case 'g':
4253 case 'G':
4254 absolute = 1000000000;
4255 break;
4256 default:
4257 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004258 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004259 if (absolute) {
4260 unsigned long long bytes;
4261 unsigned long unit;
4262
4263 bytes = (unsigned long long) i * absolute;
4264 unit = sector_size * units_per_sector;
4265 bytes += unit/2; /* round */
4266 bytes /= unit;
4267 i = bytes;
4268 }
4269 if (minus)
4270 i = -i;
4271 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004272 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004273 i = atoi(line_ptr);
4274 while (isdigit(*line_ptr)) {
4275 line_ptr++;
4276 use_default = 0;
4277 }
4278 }
4279 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004280 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004281 if (i >= low && i <= high)
4282 break;
4283 else
4284 printf(_("Value out of range.\n"));
4285 }
4286 return i;
4287}
4288
Rob Landleyb73451d2006-02-24 16:29:00 +00004289static int
4290get_partition(int warn, int max)
4291{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004292 struct pte *pe;
4293 int i;
4294
4295 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4296 pe = &ptes[i];
4297
4298 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004299 if (
4300 (
4301 label_sun != current_label_type &&
4302 label_sgi != current_label_type &&
4303 !pe->part_table->sys_ind
4304 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004305#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004306 || (
4307 label_sun == current_label_type &&
4308 (
4309 !sunlabel->partitions[i].num_sectors
4310 || !sunlabel->infos[i].id
4311 )
4312 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004313#endif
4314#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004315 || (
4316 label_sgi == current_label_type &&
4317 !sgi_get_num_sectors(i)
4318 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004319#endif
Rob Landley5527b912006-02-25 03:46:10 +00004320 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004321 fprintf(stderr,
4322 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004323 i+1
4324 );
4325 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004326 }
4327 return i;
4328}
4329
4330static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004331get_existing_partition(int warn, int max)
4332{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004333 int pno = -1;
4334 int i;
4335
4336 for (i = 0; i < max; i++) {
4337 struct pte *pe = &ptes[i];
4338 struct partition *p = pe->part_table;
4339
4340 if (p && !is_cleared_partition(p)) {
4341 if (pno >= 0)
4342 goto not_unique;
4343 pno = i;
4344 }
4345 }
4346 if (pno >= 0) {
4347 printf(_("Selected partition %d\n"), pno+1);
4348 return pno;
4349 }
4350 printf(_("No partition is defined yet!\n"));
4351 return -1;
4352
4353 not_unique:
4354 return get_partition(warn, max);
4355}
4356
4357static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004358get_nonexisting_partition(int warn, int max)
4359{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004360 int pno = -1;
4361 int i;
4362
4363 for (i = 0; i < max; i++) {
4364 struct pte *pe = &ptes[i];
4365 struct partition *p = pe->part_table;
4366
4367 if (p && is_cleared_partition(p)) {
4368 if (pno >= 0)
4369 goto not_unique;
4370 pno = i;
4371 }
4372 }
4373 if (pno >= 0) {
4374 printf(_("Selected partition %d\n"), pno+1);
4375 return pno;
4376 }
4377 printf(_("All primary partitions have been defined already!\n"));
4378 return -1;
4379
4380 not_unique:
4381 return get_partition(warn, max);
4382}
4383
4384
4385void change_units(void)
4386{
4387 display_in_cyl_units = !display_in_cyl_units;
4388 update_units();
4389 printf(_("Changing display/entry units to %s\n"),
4390 str_units(PLURAL));
4391}
4392
4393static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004394toggle_active(int i)
4395{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004396 struct pte *pe = &ptes[i];
4397 struct partition *p = pe->part_table;
4398
Rob Landleyb73451d2006-02-24 16:29:00 +00004399 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004400 fprintf(stderr,
4401 _("WARNING: Partition %d is an extended partition\n"),
4402 i + 1);
4403 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4404 pe->changed = 1;
4405}
4406
4407static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004408toggle_dos_compatibility_flag(void)
4409{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004410 dos_compatible_flag = ~dos_compatible_flag;
4411 if (dos_compatible_flag) {
4412 sector_offset = sectors;
4413 printf(_("DOS Compatibility flag is set\n"));
4414 }
4415 else {
4416 sector_offset = 1;
4417 printf(_("DOS Compatibility flag is not set\n"));
4418 }
4419}
4420
4421static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004422delete_partition(int i)
4423{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004424 struct pte *pe = &ptes[i];
4425 struct partition *p = pe->part_table;
4426 struct partition *q = pe->ext_pointer;
4427
4428/* Note that for the fifth partition (i == 4) we don't actually
4429 * decrement partitions.
4430 */
4431
4432 if (warn_geometry())
4433 return; /* C/H/S not set */
4434 pe->changed = 1;
4435
4436#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004437 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004438 sun_delete_partition(i);
4439 return;
4440 }
4441#endif
4442#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004443 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004444 sgi_delete_partition(i);
4445 return;
4446 }
4447#endif
4448
4449 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004450 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004451 partitions = 4;
4452 ptes[ext_index].ext_pointer = NULL;
4453 extended_offset = 0;
4454 }
4455 clear_partition(p);
4456 return;
4457 }
4458
4459 if (!q->sys_ind && i > 4) {
4460 /* the last one in the chain - just delete */
4461 --partitions;
4462 --i;
4463 clear_partition(ptes[i].ext_pointer);
4464 ptes[i].changed = 1;
4465 } else {
4466 /* not the last one - further ones will be moved down */
4467 if (i > 4) {
4468 /* delete this link in the chain */
4469 p = ptes[i-1].ext_pointer;
4470 *p = *q;
4471 set_start_sect(p, get_start_sect(q));
4472 set_nr_sects(p, get_nr_sects(q));
4473 ptes[i-1].changed = 1;
4474 } else if (partitions > 5) { /* 5 will be moved to 4 */
4475 /* the first logical in a longer chain */
4476 pe = &ptes[5];
4477
4478 if (pe->part_table) /* prevent SEGFAULT */
4479 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004480 get_partition_start(pe) -
4481 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004482 pe->offset = extended_offset;
4483 pe->changed = 1;
4484 }
4485
4486 if (partitions > 5) {
4487 partitions--;
4488 while (i < partitions) {
4489 ptes[i] = ptes[i+1];
4490 i++;
4491 }
4492 } else
4493 /* the only logical: clear only */
4494 clear_partition(ptes[i].part_table);
4495 }
4496}
4497
4498static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004499change_sysid(void)
4500{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004501 int i, sys, origsys;
4502 struct partition *p;
4503
Eric Andersen040f4402003-07-30 08:40:37 +00004504#ifdef CONFIG_FEATURE_SGI_LABEL
4505 /* If sgi_label then don't use get_existing_partition,
4506 let the user select a partition, since get_existing_partition()
4507 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004508 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004509 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004510 } else {
4511 i = get_partition(0, partitions);
4512 }
4513#else
4514 i = get_existing_partition(0, partitions);
4515#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004516 if (i == -1)
4517 return;
4518 p = ptes[i].part_table;
4519 origsys = sys = get_sysid(i);
4520
4521 /* if changing types T to 0 is allowed, then
4522 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004523 if (!sys && label_sgi != current_label_type &&
4524 label_sun != current_label_type && !get_nr_sects(p))
4525 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004526 printf(_("Partition %d does not exist yet!\n"), i + 1);
Rob Landley5527b912006-02-25 03:46:10 +00004527 }else{
4528 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004529 sys = read_hex (get_sys_types());
4530
Rob Landley5527b912006-02-25 03:46:10 +00004531 if (!sys && label_sgi != current_label_type &&
4532 label_sun != current_label_type)
4533 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004534 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004535 "(but not to Linux). Having partitions of\n"
4536 "type 0 is probably unwise. You can delete\n"
4537 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004538 /* break; */
4539 }
4540
Rob Landley5527b912006-02-25 03:46:10 +00004541 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004542 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004543 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004544 " an extended one or vice versa\n"
4545 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004546 break;
4547 }
4548 }
4549
4550 if (sys < 256) {
4551#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004552 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004553 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004554 "as Whole disk (5),\n"
4555 "as SunOS/Solaris expects it and "
4556 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004557#endif
4558#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004559 if (label_sgi == current_label_type &&
4560 (
4561 (i == 10 && sys != ENTIRE_DISK) ||
4562 (i == 8 && sys != 0)
4563 )
4564 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004565 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004566 "as volume header (0),\nand "
4567 "partition 11 as entire volume (6)"
4568 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004569 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004570#endif
4571 if (sys == origsys)
4572 break;
4573#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004574 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004575 sun_change_sysid(i, sys);
4576 } else
4577#endif
4578#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004579 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004580 sgi_change_sysid(i, sys);
4581 } else
4582#endif
4583 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004584
Rob Landleyb73451d2006-02-24 16:29:00 +00004585 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004586 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004587 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004588 ptes[i].changed = 1;
4589 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004590 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004591 dos_changed = 1;
4592 break;
4593 }
Rob Landley5527b912006-02-25 03:46:10 +00004594 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004595 }
4596}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004597#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4598
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004599
4600/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4601 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4602 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4603 * Lubkin Oct. 1991). */
4604
Rob Landleyb73451d2006-02-24 16:29:00 +00004605static void
4606long2chs(ulong ls, uint *c, uint *h, uint *s)
4607{
4608 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004609
4610 *c = ls / spc;
4611 ls = ls % spc;
4612 *h = ls / sectors;
4613 *s = ls % sectors + 1; /* sectors count from 1 */
4614}
4615
Rob Landleyb73451d2006-02-24 16:29:00 +00004616static void
4617check_consistency(const struct partition *p, int partition)
4618{
4619 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4620 uint pec, peh, pes; /* physical ending c, h, s */
4621 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4622 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004623
4624 if (!heads || !sectors || (partition >= 4))
4625 return; /* do not check extended partitions */
4626
4627/* physical beginning c, h, s */
4628 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4629 pbh = p->head;
4630 pbs = p->sector & 0x3f;
4631
4632/* physical ending c, h, s */
4633 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4634 peh = p->end_head;
4635 pes = p->end_sector & 0x3f;
4636
4637/* compute logical beginning (c, h, s) */
4638 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4639
4640/* compute logical ending (c, h, s) */
4641 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4642
4643/* Same physical / logical beginning? */
4644 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4645 printf(_("Partition %d has different physical/logical "
4646 "beginnings (non-Linux?):\n"), partition + 1);
4647 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4648 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4649 }
4650
4651/* Same physical / logical ending? */
4652 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4653 printf(_("Partition %d has different physical/logical "
4654 "endings:\n"), partition + 1);
4655 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4656 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4657 }
4658
4659#if 0
4660/* Beginning on cylinder boundary? */
4661 if (pbh != !pbc || pbs != 1) {
4662 printf(_("Partition %i does not start on cylinder "
4663 "boundary:\n"), partition + 1);
4664 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4665 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4666 }
4667#endif
4668
4669/* Ending on cylinder boundary? */
4670 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004671 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004672 partition + 1);
4673#if 0
4674 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4675 printf(_("should be (%d, %d, %d)\n"),
4676 pec, heads - 1, sectors);
4677#endif
4678 }
4679}
4680
4681static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004682list_disk_geometry(void)
4683{
Eric Andersen040f4402003-07-30 08:40:37 +00004684 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004685 long megabytes = bytes/1000000;
4686
4687 if (megabytes < 10000)
4688 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004689 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004690 else
4691 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004692 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004693 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004694 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004695 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004696 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004697 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004698 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004699 str_units(PLURAL),
4700 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004701}
4702
4703/*
4704 * Check whether partition entries are ordered by their starting positions.
4705 * Return 0 if OK. Return i if partition i should have been earlier.
4706 * Two separate checks: primary and logical partitions.
4707 */
4708static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004709wrong_p_order(int *prev)
4710{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004711 const struct pte *pe;
4712 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004713 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004714 int i, last_i = 0;
4715
4716 for (i = 0 ; i < partitions; i++) {
4717 if (i == 4) {
4718 last_i = 4;
4719 last_p_start_pos = 0;
4720 }
4721 pe = &ptes[i];
4722 if ((p = pe->part_table)->sys_ind) {
4723 p_start_pos = get_partition_start(pe);
4724
4725 if (last_p_start_pos > p_start_pos) {
4726 if (prev)
4727 *prev = last_i;
4728 return i;
4729 }
4730
4731 last_p_start_pos = p_start_pos;
4732 last_i = i;
4733 }
4734 }
4735 return 0;
4736}
4737
4738#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4739/*
4740 * Fix the chain of logicals.
4741 * extended_offset is unchanged, the set of sectors used is unchanged
4742 * The chain is sorted so that sectors increase, and so that
4743 * starting sectors increase.
4744 *
4745 * After this it may still be that cfdisk doesnt like the table.
4746 * (This is because cfdisk considers expanded parts, from link to
4747 * end of partition, and these may still overlap.)
4748 * Now
4749 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4750 * may help.
4751 */
4752static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004753fix_chain_of_logicals(void)
4754{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004755 int j, oj, ojj, sj, sjj;
4756 struct partition *pj,*pjj,tmp;
4757
4758 /* Stage 1: sort sectors but leave sector of part 4 */
4759 /* (Its sector is the global extended_offset.) */
4760 stage1:
4761 for (j = 5; j < partitions-1; j++) {
4762 oj = ptes[j].offset;
4763 ojj = ptes[j+1].offset;
4764 if (oj > ojj) {
4765 ptes[j].offset = ojj;
4766 ptes[j+1].offset = oj;
4767 pj = ptes[j].part_table;
4768 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4769 pjj = ptes[j+1].part_table;
4770 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4771 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004772 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004773 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004774 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004775 goto stage1;
4776 }
4777 }
4778
4779 /* Stage 2: sort starting sectors */
4780 stage2:
4781 for (j = 4; j < partitions-1; j++) {
4782 pj = ptes[j].part_table;
4783 pjj = ptes[j+1].part_table;
4784 sj = get_start_sect(pj);
4785 sjj = get_start_sect(pjj);
4786 oj = ptes[j].offset;
4787 ojj = ptes[j+1].offset;
4788 if (oj+sj > ojj+sjj) {
4789 tmp = *pj;
4790 *pj = *pjj;
4791 *pjj = tmp;
4792 set_start_sect(pj, ojj+sjj-oj);
4793 set_start_sect(pjj, oj+sj-ojj);
4794 goto stage2;
4795 }
4796 }
4797
4798 /* Probably something was changed */
4799 for (j = 4; j < partitions; j++)
4800 ptes[j].changed = 1;
4801}
4802
4803
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004804static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004805fix_partition_table_order(void)
4806{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004807 struct pte *pei, *pek;
4808 int i,k;
4809
4810 if (!wrong_p_order(NULL)) {
4811 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4812 return;
4813 }
4814
4815 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4816 /* partition i should have come earlier, move it */
4817 /* We have to move data in the MBR */
4818 struct partition *pi, *pk, *pe, pbuf;
4819 pei = &ptes[i];
4820 pek = &ptes[k];
4821
4822 pe = pei->ext_pointer;
4823 pei->ext_pointer = pek->ext_pointer;
4824 pek->ext_pointer = pe;
4825
4826 pi = pei->part_table;
4827 pk = pek->part_table;
4828
4829 memmove(&pbuf, pi, sizeof(struct partition));
4830 memmove(pi, pk, sizeof(struct partition));
4831 memmove(pk, &pbuf, sizeof(struct partition));
4832
4833 pei->changed = pek->changed = 1;
4834 }
4835
4836 if (i)
4837 fix_chain_of_logicals();
4838
4839 printf("Done.\n");
4840
4841}
4842#endif
4843
4844static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004845list_table(int xtra)
4846{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004847 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004848 int i, w;
4849
4850#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004851 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004852 sun_list_table(xtra);
4853 return;
4854 }
4855#endif
4856
4857#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004858 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004859 sgi_list_table(xtra);
4860 return;
4861 }
4862#endif
4863
4864 list_disk_geometry();
4865
4866#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004867 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004868 xbsd_print_disklabel(xtra);
4869 return;
4870 }
4871#endif
4872
4873 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4874 but if the device name ends in a digit, say /dev/foo1,
4875 then the partition is called /dev/foo1p3. */
4876 w = strlen(disk_device);
4877 if (w && isdigit(disk_device[w-1]))
4878 w++;
4879 if (w < 5)
4880 w = 5;
4881
4882 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004883 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004884
4885 for (i = 0; i < partitions; i++) {
4886 const struct pte *pe = &ptes[i];
4887
4888 p = pe->part_table;
4889 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004890 off_t psects = get_nr_sects(p);
4891 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004892 unsigned int podd = 0;
4893
4894 if (sector_size < 1024) {
4895 pblocks /= (1024 / sector_size);
4896 podd = psects % (1024 / sector_size);
4897 }
4898 if (sector_size > 1024)
4899 pblocks *= (sector_size / 1024);
4900 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004901 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004902 partname(disk_device, i+1, w+2),
4903/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4904 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004905/* start */ (unsigned long long) cround(get_partition_start(pe)),
4906/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004907 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004908/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004909/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004910/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004911 check_consistency(p, i);
4912 }
4913 }
4914
4915 /* Is partition table in disk order? It need not be, but... */
4916 /* partition table entries are not checked for correct order if this
4917 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004918 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4919 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004920 printf(_("\nPartition table entries are not in disk order\n"));
4921 }
4922}
4923
4924#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4925static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004926x_list_table(int extend)
4927{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004928 const struct pte *pe;
4929 const struct partition *p;
4930 int i;
4931
4932 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4933 disk_device, heads, sectors, cylinders);
4934 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4935 for (i = 0 ; i < partitions; i++) {
4936 pe = &ptes[i];
4937 p = (extend ? pe->ext_pointer : pe->part_table);
4938 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004939 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004940 i + 1, p->boot_ind, p->head,
4941 sector(p->sector),
4942 cylinder(p->sector, p->cyl), p->end_head,
4943 sector(p->end_sector),
4944 cylinder(p->end_sector, p->end_cyl),
4945 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4946 if (p->sys_ind)
4947 check_consistency(p, i);
4948 }
4949 }
4950}
4951#endif
4952
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004953#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004954static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004955fill_bounds(off_t *first, off_t *last)
4956{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004957 int i;
4958 const struct pte *pe = &ptes[0];
4959 const struct partition *p;
4960
4961 for (i = 0; i < partitions; pe++,i++) {
4962 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004963 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004964 first[i] = 0xffffffff;
4965 last[i] = 0;
4966 } else {
4967 first[i] = get_partition_start(pe);
4968 last[i] = first[i] + get_nr_sects(p) - 1;
4969 }
4970 }
4971}
4972
4973static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004974check(int n, uint h, uint s, uint c, off_t start)
4975{
Eric Andersend9261492004-06-28 23:50:31 +00004976 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004977
4978 real_s = sector(s) - 1;
4979 real_c = cylinder(s, c);
4980 total = (real_c * sectors + real_s) * heads + h;
4981 if (!total)
4982 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4983 if (h >= heads)
4984 fprintf(stderr,
4985 _("Partition %d: head %d greater than maximum %d\n"),
4986 n, h + 1, heads);
4987 if (real_s >= sectors)
4988 fprintf(stderr, _("Partition %d: sector %d greater than "
4989 "maximum %d\n"), n, s, sectors);
4990 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004991 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4992 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004993 if (cylinders <= 1024 && start != total)
4994 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004995 _("Partition %d: previous sectors %llu disagrees with "
4996 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004997}
4998
4999static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005000verify(void)
5001{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005002 int i, j;
5003 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00005004 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005005 struct partition *p;
5006
5007 if (warn_geometry())
5008 return;
5009
5010#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005011 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005012 verify_sun();
5013 return;
5014 }
5015#endif
5016#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005017 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005018 verify_sgi(1);
5019 return;
5020 }
5021#endif
5022
5023 fill_bounds(first, last);
5024 for (i = 0; i < partitions; i++) {
5025 struct pte *pe = &ptes[i];
5026
5027 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005028 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005029 check_consistency(p, i);
5030 if (get_partition_start(pe) < first[i])
5031 printf(_("Warning: bad start-of-data in "
5032 "partition %d\n"), i + 1);
5033 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5034 last[i]);
5035 total += last[i] + 1 - first[i];
5036 for (j = 0; j < i; j++)
5037 if ((first[i] >= first[j] && first[i] <= last[j])
5038 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5039 printf(_("Warning: partition %d overlaps "
5040 "partition %d.\n"), j + 1, i + 1);
5041 total += first[i] >= first[j] ?
5042 first[i] : first[j];
5043 total -= last[i] <= last[j] ?
5044 last[i] : last[j];
5045 }
5046 }
5047 }
5048
5049 if (extended_offset) {
5050 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005051 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005052 get_nr_sects(pex->part_table) - 1;
5053
5054 for (i = 4; i < partitions; i++) {
5055 total++;
5056 p = ptes[i].part_table;
5057 if (!p->sys_ind) {
5058 if (i != 4 || i + 1 < partitions)
5059 printf(_("Warning: partition %d "
5060 "is empty\n"), i + 1);
5061 }
5062 else if (first[i] < extended_offset ||
5063 last[i] > e_last)
5064 printf(_("Logical partition %d not entirely in "
5065 "partition %d\n"), i + 1, ext_index + 1);
5066 }
5067 }
5068
5069 if (total > heads * sectors * cylinders)
5070 printf(_("Total allocated sectors %d greater than the maximum "
5071 "%d\n"), total, heads * sectors * cylinders);
5072 else if ((total = heads * sectors * cylinders - total) != 0)
5073 printf(_("%d unallocated sectors\n"), total);
5074}
5075
5076static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005077add_partition(int n, int sys)
5078{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005079 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005080 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005081 struct partition *p = ptes[n].part_table;
5082 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005083 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005084 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005085 first[partitions], last[partitions];
5086
5087 if (p && p->sys_ind) {
5088 printf(_("Partition %d is already defined. Delete "
5089 "it before re-adding it.\n"), n + 1);
5090 return;
5091 }
5092 fill_bounds(first, last);
5093 if (n < 4) {
5094 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005095 if (display_in_cyl_units || !total_number_of_sectors)
5096 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005097 else
Eric Andersen040f4402003-07-30 08:40:37 +00005098 llimit = total_number_of_sectors - 1;
5099 limit = llimit;
5100 if (limit != llimit)
5101 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005102 if (extended_offset) {
5103 first[ext_index] = extended_offset;
5104 last[ext_index] = get_start_sect(q) +
5105 get_nr_sects(q) - 1;
5106 }
5107 } else {
5108 start = extended_offset + sector_offset;
5109 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5110 }
5111 if (display_in_cyl_units)
5112 for (i = 0; i < partitions; i++)
5113 first[i] = (cround(first[i]) - 1) * units_per_sector;
5114
5115 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5116 do {
5117 temp = start;
5118 for (i = 0; i < partitions; i++) {
5119 int lastplusoff;
5120
5121 if (start == ptes[i].offset)
5122 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005123 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005124 if (start >= first[i] && start <= lastplusoff)
5125 start = lastplusoff + 1;
5126 }
5127 if (start > limit)
5128 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005129 if (start >= temp+units_per_sector && num_read) {
Eric Andersend9261492004-06-28 23:50:31 +00005130 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005131 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005132 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005133 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005134 if (!num_read && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005135 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005136
5137 saved_start = start;
5138 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5139 0, mesg);
5140 if (display_in_cyl_units) {
5141 start = (start - 1) * units_per_sector;
5142 if (start < saved_start) start = saved_start;
5143 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005144 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005145 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00005146 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005147 if (n > 4) { /* NOT for fifth partition */
5148 struct pte *pe = &ptes[n];
5149
5150 pe->offset = start - sector_offset;
5151 if (pe->offset == extended_offset) { /* must be corrected */
5152 pe->offset++;
5153 if (sector_offset == 1)
5154 start++;
5155 }
5156 }
5157
5158 for (i = 0; i < partitions; i++) {
5159 struct pte *pe = &ptes[i];
5160
5161 if (start < pe->offset && limit >= pe->offset)
5162 limit = pe->offset - 1;
5163 if (start < first[i] && limit >= first[i])
5164 limit = first[i] - 1;
5165 }
5166 if (start > limit) {
5167 printf(_("No free sectors available\n"));
5168 if (n > 4)
5169 partitions--;
5170 return;
5171 }
5172 if (cround(start) == cround(limit)) {
5173 stop = limit;
5174 } else {
5175 snprintf(mesg, sizeof(mesg),
5176 _("Last %s or +size or +sizeM or +sizeK"),
5177 str_units(SINGULAR));
5178 stop = read_int(cround(start), cround(limit), cround(limit),
5179 cround(start), mesg);
5180 if (display_in_cyl_units) {
5181 stop = stop * units_per_sector - 1;
5182 if (stop >limit)
5183 stop = limit;
5184 }
5185 }
5186
5187 set_partition(n, 0, start, stop, sys);
5188 if (n > 4)
5189 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5190
Rob Landleyb73451d2006-02-24 16:29:00 +00005191 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005192 struct pte *pe4 = &ptes[4];
5193 struct pte *pen = &ptes[n];
5194
5195 ext_index = n;
5196 pen->ext_pointer = p;
5197 pe4->offset = extended_offset = start;
5198 pe4->sectorbuffer = xcalloc(1, sector_size);
5199 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5200 pe4->ext_pointer = pe4->part_table + 1;
5201 pe4->changed = 1;
5202 partitions = 5;
5203 }
5204}
5205
5206static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005207add_logical(void)
5208{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005209 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5210 struct pte *pe = &ptes[partitions];
5211
5212 pe->sectorbuffer = xcalloc(1, sector_size);
5213 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5214 pe->ext_pointer = pe->part_table + 1;
5215 pe->offset = 0;
5216 pe->changed = 1;
5217 partitions++;
5218 }
5219 add_partition(partitions - 1, LINUX_NATIVE);
5220}
5221
5222static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005223new_partition(void)
5224{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005225 int i, free_primary = 0;
5226
5227 if (warn_geometry())
5228 return;
5229
5230#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005231 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005232 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5233 return;
5234 }
5235#endif
5236#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005237 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005238 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5239 return;
5240 }
5241#endif
5242#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005243 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005244 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5245 "\n\tIf you want to add DOS-type partitions, create"
5246 "\n\ta new empty DOS partition table first. (Use o.)"
5247 "\n\tWARNING: "
5248 "This will destroy the present disk contents.\n"));
5249 return;
5250 }
5251#endif
5252
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005253 for (i = 0; i < 4; i++)
5254 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005255
Rob Landleyb73451d2006-02-24 16:29:00 +00005256 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005257 printf(_("The maximum number of partitions has been created\n"));
5258 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005259 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005260
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005261 if (!free_primary) {
5262 if (extended_offset)
5263 add_logical();
5264 else
5265 printf(_("You must delete some partition and add "
5266 "an extended partition first\n"));
5267 } else {
5268 char c, line[LINE_LENGTH];
5269 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5270 "partition (1-4)\n",
5271 "Command action", (extended_offset ?
5272 "l logical (5 or over)" : "e extended"));
5273 while (1) {
5274 if ((c = read_char(line)) == 'p' || c == 'P') {
5275 i = get_nonexisting_partition(0, 4);
5276 if (i >= 0)
5277 add_partition(i, LINUX_NATIVE);
5278 return;
5279 }
5280 else if (c == 'l' && extended_offset) {
5281 add_logical();
5282 return;
5283 }
5284 else if (c == 'e' && !extended_offset) {
5285 i = get_nonexisting_partition(0, 4);
5286 if (i >= 0)
5287 add_partition(i, EXTENDED);
5288 return;
5289 }
5290 else
5291 printf(_("Invalid partition number "
5292 "for type `%c'\n"), c);
5293 }
5294 }
5295}
5296
5297static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005298write_table(void)
5299{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005300 int i;
5301
Rob Landley5527b912006-02-25 03:46:10 +00005302 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005303 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005304 if (ptes[i].changed)
5305 ptes[3].changed = 1;
5306 for (i = 3; i < partitions; i++) {
5307 struct pte *pe = &ptes[i];
5308
5309 if (pe->changed) {
5310 write_part_table_flag(pe->sectorbuffer);
5311 write_sector(pe->offset, pe->sectorbuffer);
5312 }
5313 }
5314 }
5315#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005316 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005317 /* no test on change? the printf below might be mistaken */
5318 sgi_write_table();
5319 }
5320#endif
5321#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005322 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005323 int needw = 0;
5324
Rob Landleyb73451d2006-02-24 16:29:00 +00005325 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005326 if (ptes[i].changed)
5327 needw = 1;
5328 if (needw)
5329 sun_write_table();
5330 }
5331#endif
5332
5333 printf(_("The partition table has been altered!\n\n"));
5334 reread_partition_table(1);
5335}
5336
Rob Landleyb73451d2006-02-24 16:29:00 +00005337static void
5338reread_partition_table(int leave)
5339{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005340 int error = 0;
5341 int i;
5342
5343 printf(_("Calling ioctl() to re-read partition table.\n"));
5344 sync();
5345 sleep(2);
5346 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5347 error = errno;
5348 } else {
5349 /* some kernel versions (1.2.x) seem to have trouble
5350 rereading the partition table, but if asked to do it
5351 twice, the second time works. - biro@yggdrasil.com */
5352 sync();
5353 sleep(2);
5354 if ((i = ioctl(fd, BLKRRPART)) != 0)
5355 error = errno;
5356 }
5357
5358 if (i) {
5359 printf(_("\nWARNING: Re-reading the partition table "
5360 "failed with error %d: %s.\n"
5361 "The kernel still uses the old table.\n"
5362 "The new table will be used "
5363 "at the next reboot.\n"),
5364 error, strerror(error));
5365 }
5366
5367 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005368 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005369 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5370 "partitions, please see the fdisk manual page for additional\n"
5371 "information.\n"));
5372
5373 if (leave) {
5374 close(fd);
5375
5376 printf(_("Syncing disks.\n"));
5377 sync();
5378 sleep(4); /* for sync() */
5379 exit(!!i);
5380 }
5381}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005382#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005383
5384#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5385#define MAX_PER_LINE 16
5386static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005387print_buffer(char *pbuffer)
5388{
5389 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005390
5391 for (i = 0, l = 0; i < sector_size; i++, l++) {
5392 if (l == 0)
5393 printf("0x%03X:", i);
5394 printf(" %02X", (unsigned char) pbuffer[i]);
5395 if (l == MAX_PER_LINE - 1) {
5396 printf("\n");
5397 l = -1;
5398 }
5399 }
5400 if (l > 0)
5401 printf("\n");
5402 printf("\n");
5403}
5404
5405
5406static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005407print_raw(void)
5408{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005409 int i;
5410
5411 printf(_("Device: %s\n"), disk_device);
5412#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005413 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005414 print_buffer(MBRbuffer);
5415 else
5416#endif
5417 for (i = 3; i < partitions; i++)
5418 print_buffer(ptes[i].sectorbuffer);
5419}
5420
5421static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005422move_begin(int i)
5423{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005424 struct pte *pe = &ptes[i];
5425 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005426 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005427
5428 if (warn_geometry())
5429 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005430 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005431 printf(_("Partition %d has no data area\n"), i + 1);
5432 return;
5433 }
5434 first = get_partition_start(pe);
5435 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005436 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005437
5438 if (new != get_nr_sects(p)) {
5439 first = get_nr_sects(p) + get_start_sect(p) - new;
5440 set_nr_sects(p, first);
5441 set_start_sect(p, new);
5442 pe->changed = 1;
5443 }
5444}
5445
5446static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005447xselect(void)
5448{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005449 char c;
5450
Rob Landleyb73451d2006-02-24 16:29:00 +00005451 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005452 putchar('\n');
5453 c = tolower(read_char(_("Expert command (m for help): ")));
5454 switch (c) {
5455 case 'a':
5456#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005457 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005458 sun_set_alt_cyl();
5459#endif
5460 break;
5461 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005462 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005463 move_begin(get_partition(0, partitions));
5464 break;
5465 case 'c':
5466 user_cylinders = cylinders =
5467 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005468 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005469#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005470 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005471 sun_set_ncyl(cylinders);
5472#endif
Rob Landley5527b912006-02-25 03:46:10 +00005473 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005474 warn_cylinders();
5475 break;
5476 case 'd':
5477 print_raw();
5478 break;
5479 case 'e':
5480#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005481 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005482 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005483 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005484#endif
5485#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005486 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005487 sun_set_xcyl();
5488 else
5489#endif
Rob Landley5527b912006-02-25 03:46:10 +00005490 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005491 x_list_table(1);
5492 break;
5493 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005494 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005495 fix_partition_table_order();
5496 break;
5497 case 'g':
5498#ifdef CONFIG_FEATURE_SGI_LABEL
5499 create_sgilabel();
5500#endif
5501 break;
5502 case 'h':
5503 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005504 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005505 update_units();
5506 break;
5507 case 'i':
5508#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005509 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005510 sun_set_ilfact();
5511#endif
5512 break;
5513 case 'o':
5514#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005515 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005516 sun_set_rspeed();
5517#endif
5518 break;
5519 case 'p':
5520#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005521 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005522 list_table(1);
5523 else
5524#endif
5525 x_list_table(0);
5526 break;
5527 case 'q':
5528 close(fd);
5529 printf("\n");
5530 exit(0);
5531 case 'r':
5532 return;
5533 case 's':
5534 user_sectors = sectors = read_int(1, sectors, 63, 0,
5535 _("Number of sectors"));
5536 if (dos_compatible_flag) {
5537 sector_offset = sectors;
5538 fprintf(stderr, _("Warning: setting "
5539 "sector offset for DOS "
5540 "compatiblity\n"));
5541 }
5542 update_units();
5543 break;
5544 case 'v':
5545 verify();
5546 break;
5547 case 'w':
5548 write_table(); /* does not return */
5549 break;
5550 case 'y':
5551#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005552 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005553 sun_set_pcylcount();
5554#endif
5555 break;
5556 default:
5557 xmenu();
5558 }
5559 }
5560}
5561#endif /* ADVANCED mode */
5562
5563static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005564is_ide_cdrom_or_tape(const char *device)
5565{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005566 FILE *procf;
5567 char buf[100];
5568 struct stat statbuf;
5569 int is_ide = 0;
5570
5571 /* No device was given explicitly, and we are trying some
5572 likely things. But opening /dev/hdc may produce errors like
5573 "hdc: tray open or drive not ready"
5574 if it happens to be a CD-ROM drive. It even happens that
5575 the process hangs on the attempt to read a music CD.
5576 So try to be careful. This only works since 2.1.73. */
5577
5578 if (strncmp("/dev/hd", device, 7))
5579 return 0;
5580
5581 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5582 procf = fopen(buf, "r");
5583 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5584 is_ide = (!strncmp(buf, "cdrom", 5) ||
5585 !strncmp(buf, "tape", 4));
5586 else
5587 /* Now when this proc file does not exist, skip the
5588 device when it is read-only. */
5589 if (stat(device, &statbuf) == 0)
5590 is_ide = ((statbuf.st_mode & 0222) == 0);
5591
5592 if (procf)
5593 fclose(procf);
5594 return is_ide;
5595}
5596
Rob Landley5527b912006-02-25 03:46:10 +00005597
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005598static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005599try(const char *device, int user_specified)
5600{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005601 int gb;
5602
5603 disk_device = device;
5604 if (setjmp(listingbuf))
5605 return;
5606 if (!user_specified)
5607 if (is_ide_cdrom_or_tape(device))
5608 return;
5609 if ((fd = open(disk_device, type_open)) >= 0) {
5610 gb = get_boot(try_only);
5611 if (gb > 0) { /* I/O error */
5612 close(fd);
5613 } else if (gb < 0) { /* no DOS signature */
5614 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005615 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005616 return;
Rob Landley5527b912006-02-25 03:46:10 +00005617 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005618#ifdef CONFIG_FEATURE_OSF_LABEL
5619 if (btrydev(device) < 0)
5620#endif
5621 fprintf(stderr,
5622 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005623 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005624 close(fd);
5625 } else {
5626 close(fd);
5627 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005628#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005629 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005630 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005631 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005632#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005633 }
5634 } else {
5635 /* Ignore other errors, since we try IDE
5636 and SCSI hard disks which may not be
5637 installed on the system. */
5638 if (errno == EACCES) {
5639 fprintf(stderr, _("Cannot open %s\n"), device);
5640 return;
5641 }
5642 }
5643}
5644
5645/* for fdisk -l: try all things in /proc/partitions
5646 that look like a partition name (do not end in a digit) */
5647static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005648tryprocpt(void)
5649{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005650 FILE *procpt;
5651 char line[100], ptname[100], devname[120], *s;
5652 int ma, mi, sz;
5653
Manuel Novoa III cad53642003-03-19 09:13:01 +00005654 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005655
5656 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005657 if (sscanf(line, " %d %d %d %[^\n ]",
5658 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005659 continue;
5660 for (s = ptname; *s; s++);
5661 if (isdigit(s[-1]))
5662 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005663 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005664 try(devname, 0);
5665 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005666#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005667 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005668#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005669}
5670
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005671#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005672static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005673unknown_command(int c)
5674{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005675 printf(_("%c: unknown command\n"), c);
5676}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005677#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005678
Rob Landleyb73451d2006-02-24 16:29:00 +00005679int fdisk_main(int argc, char **argv)
5680{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005681 int c;
5682#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5683 int optl = 0;
5684#endif
5685#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5686 int opts = 0;
5687#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005688 /*
5689 * Calls:
5690 * fdisk -v
5691 * fdisk -l [-b sectorsize] [-u] device ...
5692 * fdisk -s [partition] ...
5693 * fdisk [-b sectorsize] [-u] device
5694 *
5695 * Options -C, -H, -S set the geometry.
5696 *
5697 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005698 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5699#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5700 "s"
5701#endif
5702 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005703 switch (c) {
5704 case 'b':
5705 /* Ugly: this sector size is really per device,
5706 so cannot be combined with multiple disks,
5707 and te same goes for the C/H/S options.
5708 */
5709 sector_size = atoi(optarg);
5710 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005711 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005712 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005713 sector_offset = 2;
5714 user_set_sector_size = 1;
5715 break;
5716 case 'C':
5717 user_cylinders = atoi(optarg);
5718 break;
5719 case 'H':
5720 user_heads = atoi(optarg);
5721 if (user_heads <= 0 || user_heads >= 256)
5722 user_heads = 0;
5723 break;
5724 case 'S':
5725 user_sectors = atoi(optarg);
5726 if (user_sectors <= 0 || user_sectors >= 64)
5727 user_sectors = 0;
5728 break;
5729 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005730#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005731 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005732#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005733 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005734#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005735 case 's':
5736 opts = 1;
5737 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005738#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005739 case 'u':
5740 display_in_cyl_units = 0;
5741 break;
5742 case 'V':
5743 case 'v':
5744 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5745 return 0;
5746 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005747 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005748 }
5749 }
5750
5751#if 0
5752 printf(_("This kernel finds the sector size itself - "
5753 "-b option ignored\n"));
5754#else
5755 if (user_set_sector_size && argc-optind != 1)
5756 printf(_("Warning: the -b (set sector size) option should"
5757 " be used with one specified device\n"));
5758#endif
5759
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005760#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005761 if (optl) {
5762 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005763#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005764 type_open = O_RDONLY;
5765 if (argc > optind) {
5766 int k;
5767#if __GNUC__
5768 /* avoid gcc warning:
5769 variable `k' might be clobbered by `longjmp' */
5770 (void)&k;
5771#endif
5772 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005773 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005774 try(argv[k], 1);
5775 } else {
5776 /* we no longer have default device names */
5777 /* but, we can use /proc/partitions instead */
5778 tryprocpt();
5779 }
5780 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005781#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005782 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005783#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005784
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005785#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005786 if (opts) {
5787 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005788 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005789
5790 nowarn = 1;
5791 type_open = O_RDONLY;
5792
5793 opts = argc - optind;
5794 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005795 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005796
5797 for (j = optind; j < argc; j++) {
5798 disk_device = argv[j];
5799 if ((fd = open(disk_device, type_open)) < 0)
5800 fdisk_fatal(unable_to_open);
5801 if (ioctl(fd, BLKGETSIZE, &size))
5802 fdisk_fatal(ioctl_error);
5803 close(fd);
5804 if (opts == 1)
5805 printf("%ld\n", size/2);
5806 else
5807 printf("%s: %ld\n", argv[j], size/2);
5808 }
5809 return 0;
5810 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005811#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005812
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005813#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005814 if (argc-optind == 1)
5815 disk_device = argv[optind];
5816 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005817 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005818
5819 get_boot(fdisk);
5820
5821#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005822 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005823 /* OSF label, and no DOS label */
5824 printf(_("Detected an OSF/1 disklabel on %s, entering "
5825 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005826 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005827 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005828 /*Why do we do this? It seems to be counter-intuitive*/
5829 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005830 /* If we return we may want to make an empty DOS label? */
5831 }
5832#endif
5833
5834 while (1) {
5835 putchar('\n');
5836 c = tolower(read_char(_("Command (m for help): ")));
5837 switch (c) {
5838 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005839 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005840 toggle_active(get_partition(1, partitions));
5841#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005842 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005843 toggle_sunflags(get_partition(1, partitions),
5844 0x01);
5845#endif
5846#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005847 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005848 sgi_set_bootpartition(
5849 get_partition(1, partitions));
5850#endif
5851 else
5852 unknown_command(c);
5853 break;
5854 case 'b':
5855#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005856 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005857 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005858 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005859 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005860 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005861 printf(_("Boot file unchanged\n"));
5862 else
5863 sgi_set_bootfile(line_ptr);
5864 } else
5865#endif
5866#ifdef CONFIG_FEATURE_OSF_LABEL
5867 bselect();
5868#endif
5869 break;
5870 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005871 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005872 toggle_dos_compatibility_flag();
5873#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005874 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005875 toggle_sunflags(get_partition(1, partitions),
5876 0x10);
5877#endif
5878#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005879 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005880 sgi_set_swappartition(
5881 get_partition(1, partitions));
5882#endif
5883 else
5884 unknown_command(c);
5885 break;
5886 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005887 {
Eric Andersen040f4402003-07-30 08:40:37 +00005888 int j;
5889#ifdef CONFIG_FEATURE_SGI_LABEL
5890 /* If sgi_label then don't use get_existing_partition,
5891 let the user select a partition, since
5892 get_existing_partition() only works for Linux-like
5893 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005894 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005895 j = get_existing_partition(1, partitions);
5896 } else {
5897 j = get_partition(1, partitions);
5898 }
5899#else
5900 j = get_existing_partition(1, partitions);
5901#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005902 if (j >= 0)
5903 delete_partition(j);
5904 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005905 break;
5906 case 'i':
5907#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005908 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005909 create_sgiinfo();
5910 else
5911#endif
5912 unknown_command(c);
5913 case 'l':
5914 list_types(get_sys_types());
5915 break;
5916 case 'm':
5917 menu();
5918 break;
5919 case 'n':
5920 new_partition();
5921 break;
5922 case 'o':
5923 create_doslabel();
5924 break;
5925 case 'p':
5926 list_table(0);
5927 break;
5928 case 'q':
5929 close(fd);
5930 printf("\n");
5931 return 0;
5932 case 's':
5933#ifdef CONFIG_FEATURE_SUN_LABEL
5934 create_sunlabel();
5935#endif
5936 break;
5937 case 't':
5938 change_sysid();
5939 break;
5940 case 'u':
5941 change_units();
5942 break;
5943 case 'v':
5944 verify();
5945 break;
5946 case 'w':
5947 write_table(); /* does not return */
5948 break;
5949#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5950 case 'x':
5951#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005952 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005953 fprintf(stderr,
5954 _("\n\tSorry, no experts menu for SGI "
5955 "partition tables available.\n\n"));
5956 } else
5957#endif
5958
5959 xselect();
5960 break;
5961#endif
5962 default:
5963 unknown_command(c);
5964 menu();
5965 }
5966 }
5967 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005968#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005969}