blob: 5d1b75b89e87c0ee52c6e687413f4df79f725699 [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)
Rob Landleyb73451d2006-02-24 16:29:00 +00004 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (Busybox 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
Eric Andersen99a75d12003-08-08 20:04:56 +00009#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000010
11#define PROC_PARTITIONS "/proc/partitions"
12
Eric Andersen256c4fd2004-05-19 09:00:00 +000013#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014#include <sys/types.h>
15#include <sys/stat.h> /* stat */
16#include <ctype.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <errno.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <setjmp.h>
24#include <assert.h> /* assert */
25#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000026#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000027#include <sys/ioctl.h>
28#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000029#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030
Eric Andersenacd244a2002-12-11 03:49:33 +000031#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
32
33/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000034#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000035
36#include <sys/utsname.h>
37
38#include "busybox.h"
39
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000040#define DKTYPENAMES
41
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000042#define BLKRRPART _IO(0x12,95) /* re-read partition table */
43#define BLKGETSIZE _IO(0x12,96) /* return device size */
44#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
45#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000046
47/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000048 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000049#undef _IOR
50#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000051#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000052
53/*
54 fdisk.h
55*/
56
57#define DEFAULT_SECTOR_SIZE 512
58#define MAX_SECTOR_SIZE 2048
59#define SECTOR_SIZE 512 /* still used in BSD code */
60#define MAXIMUM_PARTS 60
61
62#define ACTIVE_FLAG 0x80
63
64#define EXTENDED 0x05
65#define WIN98_EXTENDED 0x0f
66#define LINUX_PARTITION 0x81
67#define LINUX_SWAP 0x82
68#define LINUX_NATIVE 0x83
69#define LINUX_EXTENDED 0x85
70#define LINUX_LVM 0x8e
71#define LINUX_RAID 0xfd
72
73#define SUNOS_SWAP 3
74#define WHOLE_DISK 5
75
76#define IS_EXTENDED(i) \
77 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
78
79#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
80
81#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
82#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
83
Eric Andersen7495b0d2004-02-06 05:26:58 +000084#ifdef CONFIG_FEATURE_SUN_LABEL
85#define SCSI_IOCTL_GET_IDLUN 0x5382
86#endif
87
Eric Andersend3652bf2003-08-06 09:07:37 +000088
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000089/* including <linux/hdreg.h> also fails */
90struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000091 unsigned char heads;
92 unsigned char sectors;
93 unsigned short cylinders;
94 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000095};
96
97#define HDIO_GETGEO 0x0301 /* get device geometry */
98
99
100struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000101 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000102};
103
Rob Landleyb73451d2006-02-24 16:29:00 +0000104static uint sector_size = DEFAULT_SECTOR_SIZE;
105static uint user_set_sector_size;
106static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000107
108/*
109 * Raw disk label. For DOS-type partition tables the MBR,
110 * with descriptions of the primary partitions.
111 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000112#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000113static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000114#else
115# define MBRbuffer bb_common_bufsiz1
116#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000117
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000118#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000119static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000120#endif
121
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000122static uint heads, sectors, cylinders;
123static void update_units(void);
124
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000125
126/*
127 * return partition name - uses static storage unless buf is supplied
128 */
129static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000130partname(const char *dev, int pno, int lth)
131{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000132 static char buffer[80];
133 const char *p;
134 int w, wp;
135 int bufsiz;
136 char *bufp;
137
138 bufp = buffer;
139 bufsiz = sizeof(buffer);
140
141 w = strlen(dev);
142 p = "";
143
144 if (isdigit(dev[w-1]))
145 p = "p";
146
147 /* devfs kludge - note: fdisk partition names are not supposed
148 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000149 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000150 w -= 4;
151 p = "part";
152 }
153
154 wp = strlen(p);
155
156 if (lth) {
157 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
158 lth-wp-2, w, dev, p, pno);
159 } else {
160 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
161 }
162 return bufp;
163}
164
165struct partition {
166 unsigned char boot_ind; /* 0x80 - active */
167 unsigned char head; /* starting head */
168 unsigned char sector; /* starting sector */
169 unsigned char cyl; /* starting cylinder */
170 unsigned char sys_ind; /* What partition type */
171 unsigned char end_head; /* end head */
172 unsigned char end_sector; /* end sector */
173 unsigned char end_cyl; /* end cylinder */
174 unsigned char start4[4]; /* starting sector counting from 0 */
175 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000176} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000177
178enum failure {
179 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
180 unable_to_write
181};
182
Rob Landley5527b912006-02-25 03:46:10 +0000183enum label_type{
184 label_dos, label_sun, label_sgi, label_aix, label_osf
185};
186
Rob Landleyb73451d2006-02-24 16:29:00 +0000187enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000188
Rob Landley5527b912006-02-25 03:46:10 +0000189static enum label_type current_label_type;
190
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000191static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000192static int fd; /* the disk */
193static int partitions = 4; /* maximum partition + 1 */
194static uint display_in_cyl_units = 1;
195static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000196#ifdef CONFIG_FEATURE_FDISK_WRITABLE
197static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000198static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000199static void reread_partition_table(int leave);
200static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000201static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000202static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000203static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000204#endif
205static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000206static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000207static void get_geometry(void);
208static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000209
210#define PLURAL 0
211#define SINGULAR 1
212
213#define hex_val(c) ({ \
214 char _c = (c); \
215 isdigit(_c) ? _c - '0' : \
216 tolower(_c) + 10 - 'a'; \
217 })
218
219
220#define LINE_LENGTH 800
221#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
222 (n) * sizeof(struct partition)))
223#define sector(s) ((s) & 0x3f)
224#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
225
226#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
227 ((h) + heads * cylinder(s,c)))
228#define set_hsc(h,s,c,sector) { \
229 s = sector % sectors + 1; \
230 sector /= sectors; \
231 h = sector % heads; \
232 sector /= heads; \
233 c = sector & 0xff; \
234 s |= (sector >> 2) & 0xc0; \
235 }
236
237
Eric Andersend9261492004-06-28 23:50:31 +0000238static int32_t get_start_sect(const struct partition *p);
239static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000240
241/*
242 * per partition table entry data
243 *
244 * The four primary partitions have the same sectorbuffer (MBRbuffer)
245 * and have NULL ext_pointer.
246 * Each logical partition table entry has two pointers, one for the
247 * partition and one link to the next one.
248 */
249static struct pte {
250 struct partition *part_table; /* points into sectorbuffer */
251 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000252#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000253 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000254#endif
Eric Andersend9261492004-06-28 23:50:31 +0000255 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000256 char *sectorbuffer; /* disk sector contents */
257} ptes[MAXIMUM_PARTS];
258
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000259
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000260#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000261static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000262set_all_unchanged(void)
263{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000264 int i;
265
266 for (i = 0; i < MAXIMUM_PARTS; i++)
267 ptes[i].changed = 0;
268}
269
270static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000271set_changed(int i)
272{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000273 ptes[i].changed = 1;
274}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000275#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000276
277#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
278static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000279get_part_table(int i)
280{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000281 return ptes[i].part_table;
282}
283#endif
284
285static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000286str_units(int n)
287{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000288 if (n == 1)
289 return display_in_cyl_units ? _("cylinder") : _("sector");
290 else
291 return display_in_cyl_units ? _("cylinders") : _("sectors");
292}
293
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000294static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000295valid_part_table_flag(const char *mbuffer) {
296 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000297 return (b[510] == 0x55 && b[511] == 0xaa);
298}
299
300#ifdef CONFIG_FEATURE_FDISK_WRITABLE
301static char line_buffer[LINE_LENGTH];
302
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000303/* read line; return 0 or first char */
304static int
305read_line(void)
306{
307 static int got_eof = 0;
308
309 fflush (stdout); /* requested by niles@scyld.com */
310 line_ptr = line_buffer;
311 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
312 if (feof(stdin))
313 got_eof++; /* user typed ^D ? */
314 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000315 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
316 exit(1);
317 }
318 return 0;
319 }
320 while (*line_ptr && !isgraph(*line_ptr))
321 line_ptr++;
322 return *line_ptr;
323}
324
325static char
326read_char(const char *mesg)
327{
328 do {
329 fputs(mesg, stdout);
330 } while (!read_line());
331 return *line_ptr;
332}
333
334static char
335read_chars(const char *mesg)
336{
337 fputs(mesg, stdout);
338 if (!read_line()) {
339 *line_ptr = '\n';
340 line_ptr[1] = 0;
341 }
342 return *line_ptr;
343}
344
345static int
346read_hex(const struct systypes *sys)
347{
348 int hex;
349
Rob Landleyb73451d2006-02-24 16:29:00 +0000350 while (1) {
351 read_char(_("Hex code (type L to list codes): "));
352 if (*line_ptr == 'l' || *line_ptr == 'L')
353 list_types(sys);
354 else if (isxdigit (*line_ptr)) {
355 hex = 0;
356 do
357 hex = hex << 4 | hex_val(*line_ptr++);
358 while (isxdigit(*line_ptr));
359 return hex;
360 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000361 }
362}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000363#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000364
365#ifdef CONFIG_FEATURE_AIX_LABEL
366/*
367 * Copyright (C) Andreas Neuper, Sep 1998.
368 * This file may be redistributed under
369 * the terms of the GNU Public License.
370 */
371
372typedef struct {
373 unsigned int magic; /* expect AIX_LABEL_MAGIC */
374 unsigned int fillbytes1[124];
375 unsigned int physical_volume_id;
376 unsigned int fillbytes2[124];
377} aix_partition;
378
379#define AIX_LABEL_MAGIC 0xc9c2d4c1
380#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
381#define AIX_INFO_MAGIC 0x00072959
382#define AIX_INFO_MAGIC_SWAPPED 0x59290700
383
384#define aixlabel ((aix_partition *)MBRbuffer)
385
386
387/*
388 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000389 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
390 * Internationalization
391 *
392 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
393 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000394*/
395
Rob Landleyb73451d2006-02-24 16:29:00 +0000396static int aix_other_endian;
397static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000398
399/*
400 * only dealing with free blocks here
401 */
402
403static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000404aix_info(void)
405{
406 puts(
407 _("\n\tThere is a valid AIX label on this disk.\n"
408 "\tUnfortunately Linux cannot handle these\n"
409 "\tdisks at the moment. Nevertheless some\n"
410 "\tadvice:\n"
411 "\t1. fdisk will destroy its contents on write.\n"
412 "\t2. Be sure that this disk is NOT a still vital\n"
413 "\t part of a volume group. (Otherwise you may\n"
414 "\t erase the other disks as well, if unmirrored.)\n"
415 "\t3. Before deleting this physical volume be sure\n"
416 "\t to remove the disk logically from your AIX\n"
417 "\t machine. (Otherwise you become an AIXpert).")
418 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000419}
420
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000421static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000422check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000423{
Rob Landleyb73451d2006-02-24 16:29:00 +0000424 if (aixlabel->magic != AIX_LABEL_MAGIC &&
425 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000426 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000427 aix_other_endian = 0;
428 return 0;
429 }
430 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
431 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000432 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000433 partitions = 1016;
434 aix_volumes = 15;
435 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000436 /*aix_nolabel();*/ /* %% */
437 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000438 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000439}
440#endif /* AIX_LABEL */
441
442#ifdef CONFIG_FEATURE_OSF_LABEL
443/*
444 * Copyright (c) 1987, 1988 Regents of the University of California.
445 * All rights reserved.
446 *
447 * Redistribution and use in source and binary forms, with or without
448 * modification, are permitted provided that the following conditions
449 * are met:
450 * 1. Redistributions of source code must retain the above copyright
451 * notice, this list of conditions and the following disclaimer.
452 * 2. Redistributions in binary form must reproduce the above copyright
453 * notice, this list of conditions and the following disclaimer in the
454 * documentation and/or other materials provided with the distribution.
455 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000456 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000457 * This product includes software developed by the University of
458 * California, Berkeley and its contributors.
459 * 4. Neither the name of the University nor the names of its contributors
460 * may be used to endorse or promote products derived from this software
461 * without specific prior written permission.
462 *
463 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
464 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
465 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
466 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
467 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
468 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
469 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
470 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
471 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
472 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
473 * SUCH DAMAGE.
474 */
475
476
477#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000478#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000479#endif
480
481#ifndef BSD_MAXPARTITIONS
482#define BSD_MAXPARTITIONS 16
483#endif
484
485#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
486
487#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
488#define BSD_LABELSECTOR 1
489#define BSD_LABELOFFSET 0
490#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
491#define BSD_LABELSECTOR 0
492#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000493#elif defined (__s390__) || defined (__s390x__)
494#define BSD_LABELSECTOR 1
495#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000496#else
497#error unknown architecture
498#endif
499
500#define BSD_BBSIZE 8192 /* size of boot area, with label */
501#define BSD_SBSIZE 8192 /* max size of fs superblock */
502
503struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000504 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000505 int16_t d_type; /* drive type */
506 int16_t d_subtype; /* controller/d_type specific */
507 char d_typename[16]; /* type name, e.g. "eagle" */
508 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000509 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000510 uint32_t d_secsize; /* # of bytes per sector */
511 uint32_t d_nsectors; /* # of data sectors per track */
512 uint32_t d_ntracks; /* # of tracks per cylinder */
513 uint32_t d_ncylinders; /* # of data cylinders per unit */
514 uint32_t d_secpercyl; /* # of data sectors per cylinder */
515 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000516 /*
517 * Spares (bad sector replacements) below
518 * are not counted in d_nsectors or d_secpercyl.
519 * Spare sectors are assumed to be physical sectors
520 * which occupy space at the end of each track and/or cylinder.
521 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000522 uint16_t d_sparespertrack; /* # of spare sectors per track */
523 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000524 /*
525 * Alternate cylinders include maintenance, replacement,
526 * configuration description areas, etc.
527 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000528 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000529
530 /* hardware characteristics: */
531 /*
532 * d_interleave, d_trackskew and d_cylskew describe perturbations
533 * in the media format used to compensate for a slow controller.
534 * Interleave is physical sector interleave, set up by the formatter
535 * or controller when formatting. When interleaving is in use,
536 * logically adjacent sectors are not physically contiguous,
537 * but instead are separated by some number of sectors.
538 * It is specified as the ratio of physical sectors traversed
539 * per logical sector. Thus an interleave of 1:1 implies contiguous
540 * layout, while 2:1 implies that logical sector 0 is separated
541 * by one sector from logical sector 1.
542 * d_trackskew is the offset of sector 0 on track N
543 * relative to sector 0 on track N-1 on the same cylinder.
544 * Finally, d_cylskew is the offset of sector 0 on cylinder N
545 * relative to sector 0 on cylinder N-1.
546 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000547 uint16_t d_rpm; /* rotational speed */
548 uint16_t d_interleave; /* hardware sector interleave */
549 uint16_t d_trackskew; /* sector 0 skew, per track */
550 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
551 uint32_t d_headswitch; /* head switch time, usec */
552 uint32_t d_trkseek; /* track-to-track seek, usec */
553 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000554#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000555 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000556#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000557 uint32_t d_spare[NSPARE]; /* reserved for future use */
558 uint32_t d_magic2; /* the magic number (again) */
559 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000560 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000561 uint16_t d_npartitions; /* number of partitions in following */
562 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
563 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000564 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000565 uint32_t p_size; /* number of sectors in partition */
566 uint32_t p_offset; /* starting sector */
567 uint32_t p_fsize; /* filesystem basic fragment size */
568 uint8_t p_fstype; /* filesystem type, see below */
569 uint8_t p_frag; /* filesystem fragments per block */
570 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000571 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
572};
573
574/* d_type values: */
575#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
576#define BSD_DTYPE_MSCP 2 /* MSCP */
577#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
578#define BSD_DTYPE_SCSI 4 /* SCSI */
579#define BSD_DTYPE_ESDI 5 /* ESDI interface */
580#define BSD_DTYPE_ST506 6 /* ST506 etc. */
581#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
582#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
583#define BSD_DTYPE_FLOPPY 10 /* floppy */
584
585/* d_subtype values: */
586#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
587#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
588#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
589
590#ifdef DKTYPENAMES
591static const char * const xbsd_dktypenames[] = {
592 "unknown",
593 "SMD",
594 "MSCP",
595 "old DEC",
596 "SCSI",
597 "ESDI",
598 "ST506",
599 "HP-IB",
600 "HP-FL",
601 "type 9",
602 "floppy",
603 0
604};
605#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
606#endif
607
608/*
609 * Filesystem type and version.
610 * Used to interpret other filesystem-specific
611 * per-partition information.
612 */
613#define BSD_FS_UNUSED 0 /* unused */
614#define BSD_FS_SWAP 1 /* swap */
615#define BSD_FS_V6 2 /* Sixth Edition */
616#define BSD_FS_V7 3 /* Seventh Edition */
617#define BSD_FS_SYSV 4 /* System V */
618#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
619#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
620#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
621#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
622#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
623#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
624#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
625#define BSD_FS_ISOFS BSD_FS_ISO9660
626#define BSD_FS_BOOT 13 /* partition contains bootstrap */
627#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
628#define BSD_FS_HFS 15 /* Macintosh HFS */
629#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
630
631/* this is annoying, but it's also the way it is :-( */
632#ifdef __alpha__
633#define BSD_FS_EXT2 8 /* ext2 file system */
634#else
635#define BSD_FS_MSDOS 8 /* MS-DOS file system */
636#endif
637
638#ifdef DKTYPENAMES
639static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000640 { "\x00" "unused" }, /* BSD_FS_UNUSED */
641 { "\x01" "swap" }, /* BSD_FS_SWAP */
642 { "\x02" "Version 6" }, /* BSD_FS_V6 */
643 { "\x03" "Version 7" }, /* BSD_FS_V7 */
644 { "\x04" "System V" }, /* BSD_FS_SYSV */
645 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
646 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
647 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000648#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000649 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000650#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000651 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000652#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000653 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
654 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
655 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
656 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
657 { "\x0d" "boot" }, /* BSD_FS_BOOT */
658 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
659 { "\x0f" "HFS" }, /* BSD_FS_HFS */
660 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
661 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000662};
663#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
664
665#endif
666
667/*
668 * flags shared by various drives:
669 */
670#define BSD_D_REMOVABLE 0x01 /* removable media */
671#define BSD_D_ECC 0x02 /* supports ECC */
672#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
673#define BSD_D_RAMDISK 0x08 /* disk emulator */
674#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
675#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
676
677#endif /* OSF_LABEL */
678
679/*
680 * Copyright (C) Andreas Neuper, Sep 1998.
681 * This file may be modified and redistributed under
682 * the terms of the GNU Public License.
683 */
684
685struct device_parameter { /* 48 bytes */
686 unsigned char skew;
687 unsigned char gap1;
688 unsigned char gap2;
689 unsigned char sparecyl;
690 unsigned short pcylcount;
691 unsigned short head_vol0;
692 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
693 unsigned char cmd_tag_queue_depth;
694 unsigned char unused0;
695 unsigned short unused1;
696 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
697 unsigned short bytes;
698 unsigned short ilfact;
699 unsigned int flags; /* controller flags */
700 unsigned int datarate;
701 unsigned int retries_on_error;
702 unsigned int ms_per_word;
703 unsigned short xylogics_gap1;
704 unsigned short xylogics_syncdelay;
705 unsigned short xylogics_readdelay;
706 unsigned short xylogics_gap2;
707 unsigned short xylogics_readgate;
708 unsigned short xylogics_writecont;
709};
710
711#define SGI_VOLHDR 0x00
712/* 1 and 2 were used for drive types no longer supported by SGI */
713#define SGI_SWAP 0x03
714/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
715#define SGI_VOLUME 0x06
716#define SGI_EFS 0x07
717#define SGI_LVOL 0x08
718#define SGI_RLVOL 0x09
719#define SGI_XFS 0x0a
720#define SGI_XFSLOG 0x0b
721#define SGI_XLV 0x0c
722#define SGI_XVM 0x0d
723#define ENTIRE_DISK SGI_VOLUME
724/*
725 * controller flags
726 */
727#define SECTOR_SLIP 0x01
728#define SECTOR_FWD 0x02
729#define TRACK_FWD 0x04
730#define TRACK_MULTIVOL 0x08
731#define IGNORE_ERRORS 0x10
732#define RESEEK 0x20
733#define ENABLE_CMDTAGQ 0x40
734
735typedef struct {
736 unsigned int magic; /* expect SGI_LABEL_MAGIC */
737 unsigned short boot_part; /* active boot partition */
738 unsigned short swap_part; /* active swap partition */
739 unsigned char boot_file[16]; /* name of the bootfile */
740 struct device_parameter devparam; /* 1 * 48 bytes */
741 struct volume_directory { /* 15 * 16 bytes */
742 unsigned char vol_file_name[8]; /* a character array */
743 unsigned int vol_file_start; /* number of logical block */
744 unsigned int vol_file_size; /* number of bytes */
745 } directory[15];
746 struct sgi_partition { /* 16 * 12 bytes */
747 unsigned int num_sectors; /* number of blocks */
748 unsigned int start_sector; /* must be cylinder aligned */
749 unsigned int id;
750 } partitions[16];
751 unsigned int csum;
752 unsigned int fillbytes;
753} sgi_partition;
754
755typedef struct {
756 unsigned int magic; /* looks like a magic number */
757 unsigned int a2;
758 unsigned int a3;
759 unsigned int a4;
760 unsigned int b1;
761 unsigned short b2;
762 unsigned short b3;
763 unsigned int c[16];
764 unsigned short d[3];
765 unsigned char scsi_string[50];
766 unsigned char serial[137];
767 unsigned short check1816;
768 unsigned char installer[225];
769} sgiinfo;
770
771#define SGI_LABEL_MAGIC 0x0be5a941
772#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
773#define SGI_INFO_MAGIC 0x00072959
774#define SGI_INFO_MAGIC_SWAPPED 0x59290700
775#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000776 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000777#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000778 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000779
780#define sgilabel ((sgi_partition *)MBRbuffer)
781#define sgiparam (sgilabel->devparam)
782
783typedef struct {
784 unsigned char info[128]; /* Informative text string */
785 unsigned char spare0[14];
786 struct sun_info {
787 unsigned char spare1;
788 unsigned char id;
789 unsigned char spare2;
790 unsigned char flags;
791 } infos[8];
792 unsigned char spare1[246]; /* Boot information etc. */
793 unsigned short rspeed; /* Disk rotational speed */
794 unsigned short pcylcount; /* Physical cylinder count */
795 unsigned short sparecyl; /* extra sects per cylinder */
796 unsigned char spare2[4]; /* More magic... */
797 unsigned short ilfact; /* Interleave factor */
798 unsigned short ncyl; /* Data cylinder count */
799 unsigned short nacyl; /* Alt. cylinder count */
800 unsigned short ntrks; /* Tracks per cylinder */
801 unsigned short nsect; /* Sectors per track */
802 unsigned char spare3[4]; /* Even more magic... */
803 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000804 uint32_t start_cylinder;
805 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000806 } partitions[8];
807 unsigned short magic; /* Magic number */
808 unsigned short csum; /* Label xor'd checksum */
809} sun_partition;
810
Eric Andersen040f4402003-07-30 08:40:37 +0000811
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000812#define SUN_LABEL_MAGIC 0xDABE
813#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
814#define sunlabel ((sun_partition *)MBRbuffer)
815#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000816 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000817#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000818 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000819
Eric Andersend3652bf2003-08-06 09:07:37 +0000820
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000821#ifdef CONFIG_FEATURE_OSF_LABEL
822/*
823 Changes:
824 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
825
826 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
827 support for OSF/1 disklabels on Alpha.
828 Also fixed unaligned accesses in alpha_bootblock_checksum()
829*/
830
831#define FREEBSD_PARTITION 0xa5
832#define NETBSD_PARTITION 0xa9
833
Rob Landleyb73451d2006-02-24 16:29:00 +0000834static void xbsd_delete_part(void);
835static void xbsd_new_part(void);
836static void xbsd_write_disklabel(void);
837static int xbsd_create_disklabel(void);
838static void xbsd_edit_disklabel(void);
839static void xbsd_write_bootstrap(void);
840static void xbsd_change_fstype(void);
841static int xbsd_get_part_index(int max);
842static int xbsd_check_new_partition(int *i);
843static void xbsd_list_types(void);
844static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
845static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
846static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
847static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000848
849#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000850static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000851#endif
852
853#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000854static int xbsd_translate_fstype(int linux_type);
855static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000856static struct partition *xbsd_part;
857static int xbsd_part_index;
858#endif
859
860#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000861/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000862static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000863#else
864static char disklabelbuffer[BSD_BBSIZE];
865#endif
866
867static struct xbsd_disklabel xbsd_dlabel;
868
869#define bsd_cround(n) \
870 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
871
872/*
873 * Test whether the whole disk has BSD disk label magic.
874 *
875 * Note: often reformatting with DOS-type label leaves the BSD magic,
876 * so this does not mean that there is a BSD disk label.
877 */
878static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000879check_osf_label(void)
880{
881 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000882 return 0;
883 return 1;
884}
885
886static void xbsd_print_disklabel(int);
887
888static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000889btrydev(const char * dev)
890{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000891 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
892 return -1;
893 printf(_("\nBSD label for device: %s\n"), dev);
894 xbsd_print_disklabel (0);
895 return 0;
896}
897
898static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000899bmenu(void)
900{
901 puts (_("Command action"));
902 puts (_("\td\tdelete a BSD partition"));
903 puts (_("\te\tedit drive data"));
904 puts (_("\ti\tinstall bootstrap"));
905 puts (_("\tl\tlist known filesystem types"));
906 puts (_("\tm\tprint this menu"));
907 puts (_("\tn\tadd a new BSD partition"));
908 puts (_("\tp\tprint BSD partition table"));
909 puts (_("\tq\tquit without saving changes"));
910 puts (_("\tr\treturn to main menu"));
911 puts (_("\ts\tshow complete disklabel"));
912 puts (_("\tt\tchange a partition's filesystem id"));
913 puts (_("\tu\tchange units (cylinders/sectors)"));
914 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000915#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000916 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000917#endif
918}
919
920#if !defined (__alpha__)
921static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000922hidden(int type)
923{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000924 return type ^ 0x10;
925}
926
927static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000928is_bsd_partition_type(int type)
929{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000930 return (type == FREEBSD_PARTITION ||
931 type == hidden(FREEBSD_PARTITION) ||
932 type == NETBSD_PARTITION ||
933 type == hidden(NETBSD_PARTITION));
934}
935#endif
936
937static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000938bselect(void)
939{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000940#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000941 int t, ss;
942 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000943
Rob Landleyb73451d2006-02-24 16:29:00 +0000944 for (t = 0; t < 4; t++) {
945 p = get_part_table(t);
946 if (p && is_bsd_partition_type(p->sys_ind)) {
947 xbsd_part = p;
948 xbsd_part_index = t;
949 ss = get_start_sect(xbsd_part);
950 if (ss == 0) {
951 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
952 partname(disk_device, t+1, 0));
953 return;
954 }
955 printf(_("Reading disklabel of %s at sector %d.\n"),
956 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
957 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
958 if (xbsd_create_disklabel() == 0)
959 return;
960 break;
961 }
962 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000963
Rob Landleyb73451d2006-02-24 16:29:00 +0000964 if (t == 4) {
965 printf(_("There is no *BSD partition on %s.\n"), disk_device);
966 return;
967 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000968
969#elif defined (__alpha__)
970
Rob Landleyb73451d2006-02-24 16:29:00 +0000971 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
972 if (xbsd_create_disklabel() == 0)
973 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000974
975#endif
976
Rob Landleyb73451d2006-02-24 16:29:00 +0000977 while (1) {
978 putchar('\n');
979 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
980 case 'd':
981 xbsd_delete_part();
982 break;
983 case 'e':
984 xbsd_edit_disklabel();
985 break;
986 case 'i':
987 xbsd_write_bootstrap();
988 break;
989 case 'l':
990 xbsd_list_types();
991 break;
992 case 'n':
993 xbsd_new_part();
994 break;
995 case 'p':
996 xbsd_print_disklabel(0);
997 break;
998 case 'q':
999 close(fd);
1000 exit(EXIT_SUCCESS);
1001 case 'r':
1002 return;
1003 case 's':
1004 xbsd_print_disklabel(1);
1005 break;
1006 case 't':
1007 xbsd_change_fstype();
1008 break;
1009 case 'u':
1010 change_units();
1011 break;
1012 case 'w':
1013 xbsd_write_disklabel();
1014 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001015#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001016 case 'x':
1017 xbsd_link_part();
1018 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001019#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001020 default:
1021 bmenu();
1022 break;
1023 }
1024 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001025}
1026
1027static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001028xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001029{
Rob Landleyb73451d2006-02-24 16:29:00 +00001030 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001031
Rob Landleyb73451d2006-02-24 16:29:00 +00001032 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1033 xbsd_dlabel.d_partitions[i].p_size = 0;
1034 xbsd_dlabel.d_partitions[i].p_offset = 0;
1035 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1036 if (xbsd_dlabel.d_npartitions == i + 1)
1037 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1038 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001039}
1040
1041static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001042xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001043{
Rob Landleyb73451d2006-02-24 16:29:00 +00001044 off_t begin, end;
1045 char mesg[256];
1046 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001047
Rob Landleyb73451d2006-02-24 16:29:00 +00001048 if (!xbsd_check_new_partition(&i))
1049 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001050
1051#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001052 begin = get_start_sect(xbsd_part);
1053 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001054#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001055 begin = 0;
1056 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001057#endif
1058
Rob Landleyb73451d2006-02-24 16:29:00 +00001059 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1060 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1061 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001062
Rob Landleyb73451d2006-02-24 16:29:00 +00001063 if (display_in_cyl_units)
1064 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001065
Rob Landleyb73451d2006-02-24 16:29:00 +00001066 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1067 str_units(SINGULAR));
1068 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1069 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001070
Rob Landleyb73451d2006-02-24 16:29:00 +00001071 if (display_in_cyl_units)
1072 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001073
Rob Landleyb73451d2006-02-24 16:29:00 +00001074 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1075 xbsd_dlabel.d_partitions[i].p_offset = begin;
1076 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001077}
1078
1079static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001080xbsd_print_disklabel(int show_all)
1081{
1082 struct xbsd_disklabel *lp = &xbsd_dlabel;
1083 struct xbsd_partition *pp;
1084 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001085
Rob Landleyb73451d2006-02-24 16:29:00 +00001086 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001087#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001088 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001089#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001090 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001091#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001092 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1093 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1094 else
1095 printf(_("type: %d\n"), lp->d_type);
1096 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1097 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1098 printf(_("flags:"));
1099 if (lp->d_flags & BSD_D_REMOVABLE)
1100 printf(_(" removable"));
1101 if (lp->d_flags & BSD_D_ECC)
1102 printf(_(" ecc"));
1103 if (lp->d_flags & BSD_D_BADSECT)
1104 printf(_(" badsect"));
1105 printf("\n");
1106 /* On various machines the fields of *lp are short/int/long */
1107 /* In order to avoid problems, we cast them all to long. */
1108 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1109 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1110 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1111 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1112 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1113 printf(_("rpm: %d\n"), lp->d_rpm);
1114 printf(_("interleave: %d\n"), lp->d_interleave);
1115 printf(_("trackskew: %d\n"), lp->d_trackskew);
1116 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1117 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1118 (long) lp->d_headswitch);
1119 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1120 (long) lp->d_trkseek);
1121 printf(_("drivedata: "));
1122 for (i = NDDATA - 1; i >= 0; i--)
1123 if (lp->d_drivedata[i])
1124 break;
1125 if (i < 0)
1126 i = 0;
1127 for (j = 0; j <= i; j++)
1128 printf("%ld ", (long) lp->d_drivedata[j]);
1129 }
1130 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1131 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1132 pp = lp->d_partitions;
1133 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1134 if (pp->p_size) {
1135 if (display_in_cyl_units && lp->d_secpercyl) {
1136 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1137 'a' + i,
1138 (long) pp->p_offset / lp->d_secpercyl + 1,
1139 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1140 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1141 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1142 (long) pp->p_size / lp->d_secpercyl,
1143 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1144 );
1145 } else {
1146 printf(" %c: %8ld %8ld %8ld ",
1147 'a' + i,
1148 (long) pp->p_offset,
1149 (long) pp->p_offset + pp->p_size - 1,
1150 (long) pp->p_size
1151 );
1152 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001153
Rob Landleyb73451d2006-02-24 16:29:00 +00001154 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1155 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1156 else
1157 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001158
Rob Landleyb73451d2006-02-24 16:29:00 +00001159 switch (pp->p_fstype) {
1160 case BSD_FS_UNUSED:
1161 printf(" %5ld %5ld %5.5s ",
1162 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1163 break;
1164 case BSD_FS_BSDFFS:
1165 printf(" %5ld %5ld %5d ",
1166 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1167 break;
1168 default:
1169 printf("%22.22s", "");
1170 break;
1171 }
1172 printf("\n");
1173 }
1174 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001175}
1176
1177static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001178xbsd_write_disklabel(void)
1179{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001180#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001181 printf(_("Writing disklabel to %s.\n"), disk_device);
1182 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001183#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001184 printf(_("Writing disklabel to %s.\n"),
1185 partname(disk_device, xbsd_part_index + 1, 0));
1186 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001187#endif
1188 reread_partition_table(0); /* no exit yet */
1189}
1190
1191static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001192xbsd_create_disklabel(void)
1193{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001194 char c;
1195
1196#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001197 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001198#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001199 fprintf(stderr, _("%s contains no disklabel.\n"),
1200 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001201#endif
1202
1203 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001204 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001205 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001206 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001207#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001208 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001209 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001210#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001211 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001212#endif
1213 ) == 1) {
1214 xbsd_print_disklabel (1);
1215 return 1;
1216 } else
1217 return 0;
1218 } else if (c == 'n')
1219 return 0;
1220 }
1221}
1222
1223static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001224edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001225{
Rob Landleyb73451d2006-02-24 16:29:00 +00001226 do {
1227 fputs(mesg, stdout);
1228 printf(" (%d): ", def);
1229 if (!read_line())
1230 return def;
1231 }
1232 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1233 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001234}
1235
1236static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001237xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001238{
Rob Landleyb73451d2006-02-24 16:29:00 +00001239 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001240
Rob Landleyb73451d2006-02-24 16:29:00 +00001241 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001242
1243#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001244 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1245 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1246 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1247 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001248#endif
1249
Rob Landleyb73451d2006-02-24 16:29:00 +00001250 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1251 while (1) {
1252 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1253 _("sectors/cylinder"));
1254 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1255 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001256
Rob Landleyb73451d2006-02-24 16:29:00 +00001257 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1258 }
1259 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1260 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1261 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1262 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1263 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1264 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001265
Rob Landleyb73451d2006-02-24 16:29:00 +00001266 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001267}
1268
1269static int
1270xbsd_get_bootstrap (char *path, void *ptr, int size)
1271{
Rob Landleyb73451d2006-02-24 16:29:00 +00001272 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001273
Rob Landleyb73451d2006-02-24 16:29:00 +00001274 if ((fdb = open (path, O_RDONLY)) < 0) {
1275 perror(path);
1276 return 0;
1277 }
1278 if (read(fdb, ptr, size) < 0) {
1279 perror(path);
1280 close(fdb);
1281 return 0;
1282 }
1283 printf(" ... %s\n", path);
1284 close(fdb);
1285 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001286}
1287
1288static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001289sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001290{
Rob Landleyb73451d2006-02-24 16:29:00 +00001291 printf(_("\nSyncing disks.\n"));
1292 sync();
1293 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001294}
1295
1296static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001297xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001298{
Rob Landleyb73451d2006-02-24 16:29:00 +00001299 char *bootdir = BSD_LINUX_BOOTDIR;
1300 char path[MAXPATHLEN];
1301 char *dkbasename;
1302 struct xbsd_disklabel dl;
1303 char *d, *p, *e;
1304 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001305
Rob Landleyb73451d2006-02-24 16:29:00 +00001306 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1307 dkbasename = "sd";
1308 else
1309 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001310
Rob Landleyb73451d2006-02-24 16:29:00 +00001311 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1312 dkbasename, dkbasename, dkbasename);
1313 if (read_line()) {
1314 line_ptr[strlen(line_ptr)-1] = '\0';
1315 dkbasename = line_ptr;
1316 }
1317 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1318 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1319 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001320
Rob Landleyb73451d2006-02-24 16:29:00 +00001321/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1322 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1323 bcopy(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001324
Rob Landleyb73451d2006-02-24 16:29:00 +00001325/* The disklabel will be overwritten by 0's from bootxx anyway */
1326 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001327
Rob Landleyb73451d2006-02-24 16:29:00 +00001328 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1329 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001330 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001331 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001332
Rob Landleyb73451d2006-02-24 16:29:00 +00001333 e = d + sizeof(struct xbsd_disklabel);
1334 for (p = d; p < e; p++)
1335 if (*p) {
1336 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1337 exit(EXIT_FAILURE);
1338 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001339
Rob Landleyb73451d2006-02-24 16:29:00 +00001340 bcopy(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001341
1342#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001343 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001344#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001345 sector = 0;
1346 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001347#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001348 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001349#endif
1350
Rob Landleyb73451d2006-02-24 16:29:00 +00001351 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1352 fdisk_fatal(unable_to_seek);
1353 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1354 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001355
1356#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001357 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001358#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001359 printf(_("Bootstrap installed on %s.\n"),
1360 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001361#endif
1362
Rob Landleyb73451d2006-02-24 16:29:00 +00001363 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001364}
1365
1366static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001367xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001368{
Rob Landleyb73451d2006-02-24 16:29:00 +00001369 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001370
Rob Landleyb73451d2006-02-24 16:29:00 +00001371 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1372 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373}
1374
1375static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001376xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001377{
Rob Landleyb73451d2006-02-24 16:29:00 +00001378 char prompt[256];
1379 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001380
Rob Landleyb73451d2006-02-24 16:29:00 +00001381 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1382 do
1383 l = tolower(read_char(prompt));
1384 while (l < 'a' || l > 'a' + max - 1);
1385 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001386}
1387
1388static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001389xbsd_check_new_partition(int *i)
1390{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001391 /* room for more? various BSD flavours have different maxima */
1392 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1393 int t;
1394
1395 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1396 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1397 break;
1398
1399 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001400 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001401 "has been created\n"));
1402 return 0;
1403 }
1404 }
1405
1406 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1407
1408 if (*i >= xbsd_dlabel.d_npartitions)
1409 xbsd_dlabel.d_npartitions = (*i) + 1;
1410
1411 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001412 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001413 return 0;
1414 }
1415
1416 return 1;
1417}
1418
1419static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001420xbsd_list_types(void)
1421{
1422 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001423}
1424
1425static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001426xbsd_dkcksum(struct xbsd_disklabel *lp)
1427{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001428 u_short *start, *end;
1429 u_short sum = 0;
1430
1431 start = (u_short *) lp;
1432 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1433 while (start < end)
1434 sum ^= *start++;
1435 return sum;
1436}
1437
1438static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001439xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1440{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001441 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001442
Rob Landleyb73451d2006-02-24 16:29:00 +00001443 get_geometry();
1444 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001445
Rob Landleyb73451d2006-02-24 16:29:00 +00001446 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001447
Rob Landleyb73451d2006-02-24 16:29:00 +00001448 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1449 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001450 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001451 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001452
1453#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001454 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001455#endif
1456
1457#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001458 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001459#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001460 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001461#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001462 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1463 d->d_nsectors = sectors; /* sectors/track */
1464 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1465 d->d_ncylinders = cylinders;
1466 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1467 if (d->d_secpercyl == 0)
1468 d->d_secpercyl = 1; /* avoid segfaults */
1469 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001470
Rob Landleyb73451d2006-02-24 16:29:00 +00001471 d->d_rpm = 3600;
1472 d->d_interleave = 1;
1473 d->d_trackskew = 0;
1474 d->d_cylskew = 0;
1475 d->d_headswitch = 0;
1476 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001477
Rob Landleyb73451d2006-02-24 16:29:00 +00001478 d->d_magic2 = BSD_DISKMAGIC;
1479 d->d_bbsize = BSD_BBSIZE;
1480 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001481
1482#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001483 d->d_npartitions = 4;
1484 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001485 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001486 pp->p_offset = get_start_sect(p);
1487 pp->p_size = get_nr_sects(p);
1488 pp->p_fstype = BSD_FS_UNUSED;
1489 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001490 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001491 pp->p_offset = 0;
1492 pp->p_size = d->d_secperunit;
1493 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001494#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001495 d->d_npartitions = 3;
1496 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001497 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001498 pp->p_offset = 0;
1499 pp->p_size = d->d_secperunit;
1500 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001501#endif
1502
1503 return 1;
1504}
1505
1506/*
1507 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1508 * If it has the right magic, return 1.
1509 */
1510static int
1511xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1512{
1513 int t, sector;
1514
1515 /* p is used only to get the starting sector */
1516#if !defined (__alpha__)
1517 sector = (p ? get_start_sect(p) : 0);
1518#elif defined (__alpha__)
1519 sector = 0;
1520#endif
1521
Rob Landleyb73451d2006-02-24 16:29:00 +00001522 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1523 fdisk_fatal(unable_to_seek);
1524 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1525 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001526
Rob Landleyb73451d2006-02-24 16:29:00 +00001527 bcopy(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1528 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001529
Rob Landleyb73451d2006-02-24 16:29:00 +00001530 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001531 return 0;
1532
Rob Landleyb73451d2006-02-24 16:29:00 +00001533 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1534 d->d_partitions[t].p_size = 0;
1535 d->d_partitions[t].p_offset = 0;
1536 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001537 }
1538
Rob Landleyb73451d2006-02-24 16:29:00 +00001539 if (d->d_npartitions > BSD_MAXPARTITIONS)
1540 fprintf(stderr, _("Warning: too many partitions "
1541 "(%d, maximum is %d).\n"),
1542 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001543 return 1;
1544}
1545
1546static int
1547xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1548{
Rob Landleyb73451d2006-02-24 16:29:00 +00001549 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001550
1551#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001552 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001553#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001554 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001555#endif
1556
Rob Landleyb73451d2006-02-24 16:29:00 +00001557 d->d_checksum = 0;
1558 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001559
Rob Landleyb73451d2006-02-24 16:29:00 +00001560 /* This is necessary if we want to write the bootstrap later,
1561 otherwise we'd write the old disklabel with the bootstrap.
1562 */
1563 bcopy(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1564 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001565
1566#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001567 alpha_bootblock_checksum (disklabelbuffer);
1568 if (lseek(fd, 0, SEEK_SET) == -1)
1569 fdisk_fatal(unable_to_seek);
1570 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1571 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001572#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001573 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1574 fdisk_fatal(unable_to_seek);
1575 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1576 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001577#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001578 sync_disks();
1579 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001580}
1581
1582
1583#if !defined (__alpha__)
1584static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001585xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001586{
Rob Landleyb73451d2006-02-24 16:29:00 +00001587 switch (linux_type) {
1588 case 0x01: /* DOS 12-bit FAT */
1589 case 0x04: /* DOS 16-bit <32M */
1590 case 0x06: /* DOS 16-bit >=32M */
1591 case 0xe1: /* DOS access */
1592 case 0xe3: /* DOS R/O */
1593 case 0xf2: /* DOS secondary */
1594 return BSD_FS_MSDOS;
1595 case 0x07: /* OS/2 HPFS */
1596 return BSD_FS_HPFS;
1597 default:
1598 return BSD_FS_OTHER;
1599 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001600}
1601
1602static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001603xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001604{
Rob Landleyb73451d2006-02-24 16:29:00 +00001605 int k, i;
1606 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001607
Rob Landleyb73451d2006-02-24 16:29:00 +00001608 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001609
Rob Landleyb73451d2006-02-24 16:29:00 +00001610 if (!xbsd_check_new_partition(&i))
1611 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001612
Rob Landleyb73451d2006-02-24 16:29:00 +00001613 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001614
Rob Landleyb73451d2006-02-24 16:29:00 +00001615 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1616 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1617 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001618}
1619#endif
1620
1621#if defined (__alpha__)
1622
1623#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001624typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001625#endif
1626
1627static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001628alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001629{
Rob Landleyb73451d2006-02-24 16:29:00 +00001630 uint64_t *dp, sum;
1631 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001632
Rob Landleyb73451d2006-02-24 16:29:00 +00001633 dp = (uint64_t *)boot;
1634 sum = 0;
1635 for (i = 0; i < 63; i++)
1636 sum += dp[i];
1637 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001638}
1639#endif /* __alpha__ */
1640
1641#endif /* OSF_LABEL */
1642
1643#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1644static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001645__swap16(unsigned short x)
1646{
Eric Andersenacd244a2002-12-11 03:49:33 +00001647 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001648}
1649
Eric Andersenacd244a2002-12-11 03:49:33 +00001650static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001651__swap32(uint32_t x)
1652{
1653 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001654 ((x & 0xFF00) << 8) |
1655 ((x & 0xFF0000) >> 8) |
1656 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001657}
1658#endif
1659
1660#ifdef CONFIG_FEATURE_SGI_LABEL
1661/*
1662 *
1663 * fdisksgilabel.c
1664 *
1665 * Copyright (C) Andreas Neuper, Sep 1998.
1666 * This file may be modified and redistributed under
1667 * the terms of the GNU Public License.
1668 *
1669 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1670 * Internationalization
1671 */
1672
1673
Rob Landleyb73451d2006-02-24 16:29:00 +00001674static int sgi_other_endian;
1675static int debug;
1676static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001677
1678/*
1679 * only dealing with free blocks here
1680 */
1681
Rob Landleyb73451d2006-02-24 16:29:00 +00001682typedef struct {
1683 unsigned int first;
1684 unsigned int last;
1685} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001686static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1687
1688static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001689setfreelist(int i, unsigned int f, unsigned int l)
1690{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001691 freelist[i].first = f;
1692 freelist[i].last = l;
1693}
1694
1695static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001696add2freelist(unsigned int f, unsigned int l)
1697{
1698 int i;
1699 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001700 if (freelist[i].last == 0)
1701 break;
1702 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001703}
1704
1705static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001706clearfreelist(void)
1707{
Eric Andersen040f4402003-07-30 08:40:37 +00001708 int i;
1709
1710 for (i = 0; i < 17 ; i++)
1711 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001712}
1713
Eric Andersen040f4402003-07-30 08:40:37 +00001714static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001715isinfreelist(unsigned int b)
1716{
Eric Andersen040f4402003-07-30 08:40:37 +00001717 int i;
1718
1719 for (i = 0; i < 17 ; i++)
1720 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001721 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001722 return 0;
1723}
1724 /* return last vacant block of this stride (never 0). */
1725 /* the '>=' is not quite correct, but simplifies the code */
1726/*
1727 * end of free blocks section
1728 */
1729
1730static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001731/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1732/* 0x01 */ { "\x01" "SGI trkrepl" },
1733/* 0x02 */ { "\x02" "SGI secrepl" },
1734/* SGI_SWAP */ { "\x03" "SGI raw" },
1735/* 0x04 */ { "\x04" "SGI bsd" },
1736/* 0x05 */ { "\x05" "SGI sysv" },
1737/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1738/* SGI_EFS */ { "\x07" "SGI efs" },
1739/* 0x08 */ { "\x08" "SGI lvol" },
1740/* 0x09 */ { "\x09" "SGI rlvol" },
1741/* SGI_XFS */ { "\x0a" "SGI xfs" },
1742/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1743/* SGI_XLV */ { "\x0c" "SGI xlv" },
1744/* SGI_XVM */ { "\x0d" "SGI xvm" },
1745/* LINUX_SWAP */ { "\x82" "Linux swap" },
1746/* LINUX_NATIVE */ { "\x83" "Linux native" },
1747/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1748/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1749 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001750};
1751
1752
1753static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001754sgi_get_nsect(void)
1755{
1756 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001757}
1758
1759static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001760sgi_get_ntrks(void)
1761{
1762 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001763}
1764
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001765static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001766two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1767{
1768 int i = 0;
1769 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001770
Rob Landleyb73451d2006-02-24 16:29:00 +00001771 size /= sizeof(unsigned int);
1772 for (i = 0; i < size; i++)
1773 sum -= SGI_SSWAP32(base[i]);
1774 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001775}
1776
1777static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001778check_sgi_label(void)
1779{
1780 if (sizeof(sgilabel) > 512) {
1781 fprintf(stderr,
1782 _("According to MIPS Computer Systems, Inc the "
1783 "Label must not contain more than 512 bytes\n"));
1784 exit(1);
1785 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001786
Rob Landleyb73451d2006-02-24 16:29:00 +00001787 if (sgilabel->magic != SGI_LABEL_MAGIC
1788 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001789 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001790 return 0;
1791 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001792
Rob Landleyb73451d2006-02-24 16:29:00 +00001793 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1794 /*
1795 * test for correct checksum
1796 */
1797 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1798 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001799 fprintf(stderr,
1800 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001801 }
1802 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001803 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001804 partitions = 16;
1805 sgi_volumes = 15;
1806 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001807}
1808
Eric Andersen040f4402003-07-30 08:40:37 +00001809static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001810sgi_get_start_sector(int i)
1811{
1812 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001813}
1814
Eric Andersen040f4402003-07-30 08:40:37 +00001815static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001816sgi_get_num_sectors(int i)
1817{
1818 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001819}
1820
1821static int
Eric Andersen040f4402003-07-30 08:40:37 +00001822sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001823{
Rob Landleyb73451d2006-02-24 16:29:00 +00001824 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001825}
1826
1827static int
1828sgi_get_bootpartition(void)
1829{
Rob Landleyb73451d2006-02-24 16:29:00 +00001830 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001831}
1832
1833static int
1834sgi_get_swappartition(void)
1835{
Rob Landleyb73451d2006-02-24 16:29:00 +00001836 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001837}
1838
1839static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001840sgi_list_table(int xtra)
1841{
1842 int i, w, wd;
1843 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001844
Rob Landleyb73451d2006-02-24 16:29:00 +00001845 if(xtra) {
1846 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1847 "%d cylinders, %d physical cylinders\n"
1848 "%d extra sects/cyl, interleave %d:1\n"
1849 "%s\n"
1850 "Units = %s of %d * 512 bytes\n\n"),
1851 disk_device, heads, sectors, cylinders,
1852 SGI_SSWAP16(sgiparam.pcylcount),
1853 SGI_SSWAP16(sgiparam.sparecyl),
1854 SGI_SSWAP16(sgiparam.ilfact),
1855 (char *)sgilabel,
1856 str_units(PLURAL), units_per_sector);
1857 } else {
1858 printf( _("\nDisk %s (SGI disk label): "
1859 "%d heads, %d sectors, %d cylinders\n"
1860 "Units = %s of %d * 512 bytes\n\n"),
1861 disk_device, heads, sectors, cylinders,
1862 str_units(PLURAL), units_per_sector );
1863 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001864
Rob Landleyb73451d2006-02-24 16:29:00 +00001865 w = strlen(disk_device);
1866 wd = strlen(_("Device"));
1867 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001868 w = wd;
1869
Rob Landleyb73451d2006-02-24 16:29:00 +00001870 printf(_("----- partitions -----\n"
1871 "Pt# %*s Info Start End Sectors Id System\n"),
1872 w + 2, _("Device"));
1873 for (i = 0 ; i < partitions; i++) {
1874 if( sgi_get_num_sectors(i) || debug ) {
1875 uint32_t start = sgi_get_start_sector(i);
1876 uint32_t len = sgi_get_num_sectors(i);
1877 kpi++; /* only count nonempty partitions */
1878 printf(
1879 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1880/* fdisk part number */ i+1,
1881/* device */ partname(disk_device, kpi, w+3),
1882/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1883/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1884/* start */ (long) scround(start),
1885/* end */ (long) scround(start+len)-1,
1886/* no odd flag on end */(long) len,
1887/* type id */ sgi_get_sysid(i),
1888/* type name */ partition_type(sgi_get_sysid(i)));
1889 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001890 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001891 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1892 "----- Directory Entries -----\n"),
1893 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001894 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001895 if (sgilabel->directory[i].vol_file_size) {
1896 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1897 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1898 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001899
Rob Landleyb73451d2006-02-24 16:29:00 +00001900 printf(_("%2d: %-10s sector%5u size%8u\n"),
1901 i, (char*)name, (unsigned int) start, (unsigned int) len);
1902 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001903 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001904}
1905
1906static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001907sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001908{
Rob Landleyb73451d2006-02-24 16:29:00 +00001909 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001910}
1911
Eric Andersen040f4402003-07-30 08:40:37 +00001912static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001913sgi_get_lastblock(void)
1914{
1915 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001916}
1917
1918static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001919sgi_set_swappartition(int i)
1920{
1921 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001922}
1923
1924static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001925sgi_check_bootfile(const char* aFile)
1926{
1927 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1928 printf(_("\nInvalid Bootfile!\n"
1929 "\tThe bootfile must be an absolute non-zero pathname,\n"
1930 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1931 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001932 } else {
1933 if (strlen(aFile) > 16) {
1934 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001935 "16 bytes maximum.\n"));
1936 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001937 } else {
1938 if (aFile[0] != '/') {
1939 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001940 "fully qualified pathname.\n"));
1941 return 0;
1942 }
Eric Andersen040f4402003-07-30 08:40:37 +00001943 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001944 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001945 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001946 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1947 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001948 /* filename is correct and did change */
1949 return 1;
1950 }
1951 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001952}
1953
1954static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001955sgi_get_bootfile(void)
1956{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001957 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001958}
1959
1960static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001961sgi_set_bootfile(const char* aFile)
1962{
1963 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001964
Rob Landleyb73451d2006-02-24 16:29:00 +00001965 if (sgi_check_bootfile(aFile)) {
1966 while (i < 16) {
1967 if ((aFile[i] != '\n') /* in principle caught again by next line */
1968 && (strlen(aFile) > i))
1969 sgilabel->boot_file[i] = aFile[i];
1970 else
1971 sgilabel->boot_file[i] = 0;
1972 i++;
1973 }
1974 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001975 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001976}
1977
1978static void
1979create_sgiinfo(void)
1980{
Rob Landleyb73451d2006-02-24 16:29:00 +00001981 /* I keep SGI's habit to write the sgilabel to the second block */
1982 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1983 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1984 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001985}
1986
Eric Andersen040f4402003-07-30 08:40:37 +00001987static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001988
1989static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001990sgi_write_table(void)
1991{
1992 sgilabel->csum = 0;
1993 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1994 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1995 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00001996 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00001997
1998 if (lseek(fd, 0, SEEK_SET) < 0)
1999 fdisk_fatal(unable_to_seek);
2000 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
2001 fdisk_fatal(unable_to_write);
2002 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2003 /*
2004 * keep this habit of first writing the "sgilabel".
2005 * I never tested whether it works without (AN 981002).
2006 */
2007 sgiinfo *info = fill_sgiinfo();
2008 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2009 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2010 fdisk_fatal(unable_to_seek);
2011 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2012 fdisk_fatal(unable_to_write);
2013 free(info);
2014 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002015}
2016
2017static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002018compare_start(int *x, int *y)
2019{
2020 /*
2021 * sort according to start sectors
2022 * and prefers largest partition:
2023 * entry zero is entire disk entry
2024 */
2025 unsigned int i = *x;
2026 unsigned int j = *y;
2027 unsigned int a = sgi_get_start_sector(i);
2028 unsigned int b = sgi_get_start_sector(j);
2029 unsigned int c = sgi_get_num_sectors(i);
2030 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002031
Rob Landleyb73451d2006-02-24 16:29:00 +00002032 if (a == b)
2033 return (d > c) ? 1 : (d == c) ? 0 : -1;
2034 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002035}
2036
2037
2038static int
Eric Andersen040f4402003-07-30 08:40:37 +00002039verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002040{
Rob Landleyb73451d2006-02-24 16:29:00 +00002041 int Index[16]; /* list of valid partitions */
2042 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2043 int entire = 0, i = 0;
2044 unsigned int start = 0;
2045 long long gap = 0; /* count unused blocks */
2046 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002047
Rob Landleyb73451d2006-02-24 16:29:00 +00002048 clearfreelist();
2049 for (i = 0; i < 16; i++) {
2050 if (sgi_get_num_sectors(i) != 0) {
2051 Index[sortcount++] = i;
2052 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2053 if (entire++ == 1) {
2054 if (verbose)
2055 printf(_("More than one entire disk entry present.\n"));
2056 }
2057 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002058 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002059 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002060 if (sortcount == 0) {
2061 if (verbose)
2062 printf(_("No partitions defined\n"));
2063 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2064 }
2065 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2066 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2067 if ((Index[0] != 10) && verbose)
2068 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2069 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2070 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002071 "at block 0,\n"
2072 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002073 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002074 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002075 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2076 printf(_("The entire disk partition is only %d diskblock large,\n"
2077 "but the disk is %d diskblocks long.\n"),
2078 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002079 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002080 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002081 if (verbose)
2082 printf(_("One Partition (#11) should cover the entire disk.\n"));
2083 if (debug > 2)
2084 printf("sysid=%d\tpartition=%d\n",
2085 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002086 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002087 for (i = 1, start = 0; i < sortcount; i++) {
2088 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2089
2090 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2091 if (debug) /* I do not understand how some disks fulfil it */
2092 if (verbose)
2093 printf(_("Partition %d does not start on cylinder boundary.\n"),
2094 Index[i]+1);
2095 }
2096 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2097 if (debug) /* I do not understand how some disks fulfil it */
2098 if (verbose)
2099 printf(_("Partition %d does not end on cylinder boundary.\n"),
2100 Index[i]+1);
2101 }
2102 /* We cannot handle several "entire disk" entries. */
2103 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2104 if (start > sgi_get_start_sector(Index[i])) {
2105 if (verbose)
2106 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2107 Index[i-1]+1, Index[i]+1,
2108 start - sgi_get_start_sector(Index[i]));
2109 if (gap > 0) gap = -gap;
2110 if (gap == 0) gap = -1;
2111 }
2112 if (start < sgi_get_start_sector(Index[i])) {
2113 if (verbose)
2114 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2115 sgi_get_start_sector(Index[i]) - start,
2116 start, sgi_get_start_sector(Index[i])-1);
2117 gap += sgi_get_start_sector(Index[i]) - start;
2118 add2freelist(start, sgi_get_start_sector(Index[i]));
2119 }
2120 start = sgi_get_start_sector(Index[i])
2121 + sgi_get_num_sectors(Index[i]);
2122 if (debug > 1) {
2123 if (verbose)
2124 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2125 sgi_get_start_sector(Index[i]),
2126 sgi_get_num_sectors(Index[i]),
2127 sgi_get_sysid(Index[i]));
2128 }
2129 }
2130 if (start < lastblock) {
2131 if (verbose)
2132 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2133 lastblock - start, start, lastblock-1);
2134 gap += lastblock - start;
2135 add2freelist(start, lastblock);
2136 }
2137 /*
2138 * Done with arithmetics
2139 * Go for details now
2140 */
2141 if (verbose) {
2142 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2143 printf(_("\nThe boot partition does not exist.\n"));
2144 }
2145 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2146 printf(_("\nThe swap partition does not exist.\n"));
2147 } else {
2148 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2149 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2150 printf(_("\nThe swap partition has no swap type.\n"));
2151 }
2152 if (sgi_check_bootfile("/unix"))
2153 printf(_("\tYou have chosen an unusual boot file name.\n"));
2154 }
2155 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002156}
2157
2158static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002159sgi_gaps(void)
2160{
2161 /*
2162 * returned value is:
2163 * = 0 : disk is properly filled to the rim
2164 * < 0 : there is an overlap
2165 * > 0 : there is still some vacant space
2166 */
2167 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002168}
2169
2170static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002171sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002172{
Rob Landleyb73451d2006-02-24 16:29:00 +00002173 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2174 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2175 return;
2176 }
2177 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2178 && (sgi_get_start_sector(i) < 1) ) {
2179 read_chars(
2180 _("It is highly recommended that the partition at offset 0\n"
2181 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2182 "retrieve from its directory standalone tools like sash and fx.\n"
2183 "Only the \"SGI volume\" entire disk section may violate this.\n"
2184 "Type YES if you are sure about tagging this partition differently.\n"));
2185 if (strcmp(line_ptr, _("YES\n")))
2186 return;
2187 }
2188 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002189}
2190
2191/* returns partition index of first entry marked as entire disk */
2192static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002193sgi_entire(void)
2194{
2195 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002196
Rob Landleyb73451d2006-02-24 16:29:00 +00002197 for (i = 0; i < 16; i++)
2198 if (sgi_get_sysid(i) == SGI_VOLUME)
2199 return i;
2200 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002201}
2202
2203static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002204sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2205{
2206 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2207 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2208 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2209 set_changed(i);
2210 if (sgi_gaps() < 0) /* rebuild freelist */
2211 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002212}
2213
2214static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002215sgi_set_entire(void)
2216{
2217 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002218
Rob Landleyb73451d2006-02-24 16:29:00 +00002219 for (n = 10; n < partitions; n++) {
2220 if(!sgi_get_num_sectors(n) ) {
2221 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2222 break;
2223 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002224 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002225}
2226
2227static void
2228sgi_set_volhdr(void)
2229{
Rob Landleyb73451d2006-02-24 16:29:00 +00002230 int n;
2231
2232 for (n = 8; n < partitions; n++) {
2233 if (!sgi_get_num_sectors(n)) {
2234 /*
2235 * 5 cylinders is an arbitrary value I like
2236 * IRIX 5.3 stored files in the volume header
2237 * (like sash, symmon, fx, ide) with ca. 3200
2238 * sectors.
2239 */
2240 if (heads * sectors * 5 < sgi_get_lastblock())
2241 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2242 break;
2243 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002244 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002245}
2246
2247static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002248sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002249{
Rob Landleyb73451d2006-02-24 16:29:00 +00002250 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002251}
2252
2253static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002254sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002255{
Rob Landleyb73451d2006-02-24 16:29:00 +00002256 char mesg[256];
2257 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002258
Rob Landleyb73451d2006-02-24 16:29:00 +00002259 if (n == 10) {
2260 sys = SGI_VOLUME;
2261 } else if (n == 8) {
2262 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002263 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002264 if(sgi_get_num_sectors(n)) {
2265 printf(_("Partition %d is already defined. Delete "
2266 "it before re-adding it.\n"), n + 1);
2267 return;
2268 }
2269 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2270 printf(_("Attempting to generate entire disk entry automatically.\n"));
2271 sgi_set_entire();
2272 sgi_set_volhdr();
2273 }
2274 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2275 printf(_("The entire disk is already covered with partitions.\n"));
2276 return;
2277 }
2278 if (sgi_gaps() < 0) {
2279 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2280 return;
2281 }
2282 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2283 while (1) {
2284 if(sys == SGI_VOLUME) {
2285 last = sgi_get_lastblock();
2286 first = read_int(0, 0, last-1, 0, mesg);
2287 if (first != 0) {
2288 printf(_("It is highly recommended that eleventh partition\n"
2289 "covers the entire disk and is of type `SGI volume'\n"));
2290 }
2291 } else {
2292 first = freelist[0].first;
2293 last = freelist[0].last;
2294 first = read_int(scround(first), scround(first), scround(last)-1,
2295 0, mesg);
2296 }
2297 if (display_in_cyl_units)
2298 first *= units_per_sector;
2299 else
2300 first = first; /* align to cylinder if you know how ... */
2301 if(!last )
2302 last = isinfreelist(first);
2303 if(last == 0) {
2304 printf(_("You will get a partition overlap on the disk. "
2305 "Fix it first!\n"));
2306 } else
2307 break;
2308 }
2309 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2310 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2311 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002312 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002313 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002314 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002315 last = last; /* align to cylinder if You know how ... */
2316 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2317 printf(_("It is highly recommended that eleventh partition\n"
2318 "covers the entire disk and is of type `SGI volume'\n"));
2319 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002320}
2321
Eric Andersen040f4402003-07-30 08:40:37 +00002322#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002323static void
2324create_sgilabel(void)
2325{
Rob Landleyb73451d2006-02-24 16:29:00 +00002326 struct hd_geometry geometry;
2327 struct {
2328 unsigned int start;
2329 unsigned int nsect;
2330 int sysid;
2331 } old[4];
2332 int i = 0;
2333 long longsectors; /* the number of sectors on the device */
2334 int res; /* the result from the ioctl */
2335 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002336
Rob Landleyb73451d2006-02-24 16:29:00 +00002337 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002338
Rob Landleyb73451d2006-02-24 16:29:00 +00002339 fprintf( stderr,
2340 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2341 "until you decide to write them. After that, of course, the previous\n"
2342 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002343
Rob Landleyb73451d2006-02-24 16:29:00 +00002344 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
2345 res = ioctl(fd, BLKGETSIZE, &longsectors);
2346 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2347 heads = geometry.heads;
2348 sectors = geometry.sectors;
2349 if (res == 0) {
2350 /* the get device size ioctl was successful */
2351 cylinders = longsectors / (heads * sectors);
2352 cylinders /= sec_fac;
2353 } else {
2354 /* otherwise print error and use truncated version */
2355 cylinders = geometry.cylinders;
2356 fprintf(stderr,
2357 _("Warning: BLKGETSIZE ioctl failed on %s. "
2358 "Using geometry cylinder value of %d.\n"
2359 "This value may be truncated for devices"
2360 " > 33.8 GB.\n"), disk_device, cylinders);
2361 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002362 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002363 for (i = 0; i < 4; i++) {
2364 old[i].sysid = 0;
2365 if (valid_part_table_flag(MBRbuffer)) {
2366 if(get_part_table(i)->sys_ind) {
2367 old[i].sysid = get_part_table(i)->sys_ind;
2368 old[i].start = get_start_sect(get_part_table(i));
2369 old[i].nsect = get_nr_sects(get_part_table(i));
2370 printf(_("Trying to keep parameters of partition %d.\n"), i);
2371 if (debug)
2372 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2373 old[i].sysid, old[i].start, old[i].nsect);
2374 }
2375 }
2376 }
Eric Andersen040f4402003-07-30 08:40:37 +00002377
Rob Landleyb73451d2006-02-24 16:29:00 +00002378 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2379 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2380 sgilabel->boot_part = SGI_SSWAP16(0);
2381 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002382
Rob Landleyb73451d2006-02-24 16:29:00 +00002383 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2384 memset(sgilabel->boot_file, 0, 16);
2385 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002386
Rob Landleyb73451d2006-02-24 16:29:00 +00002387 sgilabel->devparam.skew = (0);
2388 sgilabel->devparam.gap1 = (0);
2389 sgilabel->devparam.gap2 = (0);
2390 sgilabel->devparam.sparecyl = (0);
2391 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2392 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2393 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002394 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002395 sgilabel->devparam.cmd_tag_queue_depth = (0);
2396 sgilabel->devparam.unused0 = (0);
2397 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2398 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002399 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002400 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2401 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2402 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002403 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002404 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2405 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2406 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2407 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2408 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2409 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2410 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2411 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2412 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2413 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2414 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002415 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002416 partitions = 16;
2417 sgi_volumes = 15;
2418 sgi_set_entire();
2419 sgi_set_volhdr();
2420 for (i = 0; i < 4; i++) {
2421 if(old[i].sysid) {
2422 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2423 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002424 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002425}
2426
2427static void
2428sgi_set_xcyl(void)
2429{
Rob Landleyb73451d2006-02-24 16:29:00 +00002430 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002431}
Eric Andersen040f4402003-07-30 08:40:37 +00002432#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002433
2434/* _____________________________________________________________
2435 */
2436
Eric Andersen040f4402003-07-30 08:40:37 +00002437static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002438fill_sgiinfo(void)
2439{
Rob Landleyb73451d2006-02-24 16:29:00 +00002440 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002441
Rob Landleyb73451d2006-02-24 16:29:00 +00002442 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2443 info->b1 = SGI_SSWAP32(-1);
2444 info->b2 = SGI_SSWAP16(-1);
2445 info->b3 = SGI_SSWAP16(1);
2446 /* You may want to replace this string !!!!!!! */
2447 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2448 strcpy( (char*)info->serial, "0000" );
2449 info->check1816 = SGI_SSWAP16(18*256 +16 );
2450 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2451 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002452}
2453#endif /* SGI_LABEL */
2454
2455
2456#ifdef CONFIG_FEATURE_SUN_LABEL
2457/*
2458 * fdisksunlabel.c
2459 *
2460 * I think this is mostly, or entirely, due to
2461 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2462 *
2463 * Merged with fdisk for other architectures, aeb, June 1998.
2464 *
2465 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2466 * Internationalization
2467 */
2468
2469
Rob Landleyb73451d2006-02-24 16:29:00 +00002470static int sun_other_endian;
2471static int scsi_disk;
2472static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002473
2474#ifndef IDE0_MAJOR
2475#define IDE0_MAJOR 3
2476#endif
2477#ifndef IDE1_MAJOR
2478#define IDE1_MAJOR 22
2479#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002480
Rob Landleyb73451d2006-02-24 16:29:00 +00002481static void
2482guess_device_type(void)
2483{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002484 struct stat bootstat;
2485
Rob Landleyb73451d2006-02-24 16:29:00 +00002486 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002487 scsi_disk = 0;
2488 floppy = 0;
2489 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002490 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2491 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002492 scsi_disk = 0;
2493 floppy = 0;
2494 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002495 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002496 scsi_disk = 0;
2497 floppy = 1;
2498 } else {
2499 scsi_disk = 1;
2500 floppy = 0;
2501 }
2502}
2503
2504static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002505 { "\x00" "Empty" }, /* 0 */
2506 { "\x01" "Boot" }, /* 1 */
2507 { "\x02" "SunOS root" }, /* 2 */
2508 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2509 { "\x04" "SunOS usr" }, /* 4 */
2510 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2511 { "\x06" "SunOS stand" }, /* 6 */
2512 { "\x07" "SunOS var" }, /* 7 */
2513 { "\x08" "SunOS home" }, /* 8 */
2514 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2515 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2516 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002517/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002518 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2519 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002520};
2521
2522
2523static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002524set_sun_partition(int i, uint start, uint stop, int sysid)
2525{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002526 sunlabel->infos[i].id = sysid;
2527 sunlabel->partitions[i].start_cylinder =
2528 SUN_SSWAP32(start / (heads * sectors));
2529 sunlabel->partitions[i].num_sectors =
2530 SUN_SSWAP32(stop - start);
2531 set_changed(i);
2532}
2533
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002534static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002535check_sun_label(void)
2536{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002537 unsigned short *ush;
2538 int csum;
2539
Rob Landleyb73451d2006-02-24 16:29:00 +00002540 if (sunlabel->magic != SUN_LABEL_MAGIC
2541 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002542 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002543 sun_other_endian = 0;
2544 return 0;
2545 }
2546 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2547 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2548 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2549 if (csum) {
2550 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2551 "Probably you'll have to set all the values,\n"
2552 "e.g. heads, sectors, cylinders and partitions\n"
2553 "or force a fresh label (s command in main menu)\n"));
2554 } else {
2555 heads = SUN_SSWAP16(sunlabel->ntrks);
2556 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2557 sectors = SUN_SSWAP16(sunlabel->nsect);
2558 }
2559 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002560 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002561 partitions = 8;
2562 return 1;
2563}
2564
2565static const struct sun_predefined_drives {
2566 const char *vendor;
2567 const char *model;
2568 unsigned short sparecyl;
2569 unsigned short ncyl;
2570 unsigned short nacyl;
2571 unsigned short pcylcount;
2572 unsigned short ntrks;
2573 unsigned short nsect;
2574 unsigned short rspeed;
2575} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002576 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2577 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2578 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2579 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2580 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2581 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2582 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2583 { "","SUN0104",1,974,2,1019,6,35,3662},
2584 { "","SUN0207",4,1254,2,1272,9,36,3600},
2585 { "","SUN0327",3,1545,2,1549,9,46,3600},
2586 { "","SUN0340",0,1538,2,1544,6,72,4200},
2587 { "","SUN0424",2,1151,2,2500,9,80,4400},
2588 { "","SUN0535",0,1866,2,2500,7,80,5400},
2589 { "","SUN0669",5,1614,2,1632,15,54,3600},
2590 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2591 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2592 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2593 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2594 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002595};
2596
2597static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002598sun_autoconfigure_scsi(void)
2599{
2600 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002601
2602#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002603 unsigned int id[2];
2604 char buffer[2048];
2605 char buffer2[2048];
2606 FILE *pfd;
2607 char *vendor;
2608 char *model;
2609 char *q;
2610 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002611
Rob Landleyb73451d2006-02-24 16:29:00 +00002612 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2613 sprintf(buffer,
2614 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002615#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002616 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002617#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002618 /* This is very wrong (works only if you have one HBA),
2619 but I haven't found a way how to get hostno
2620 from the current kernel */
2621 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002622#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002623 (id[0]>>16) & 0xff,
2624 id[0] & 0xff,
2625 (id[0]>>8) & 0xff
2626 );
2627 pfd = fopen("/proc/scsi/scsi","r");
2628 if (pfd) {
2629 while (fgets(buffer2, 2048, pfd)) {
2630 if (!strcmp(buffer, buffer2)) {
2631 if (fgets(buffer2,2048,pfd)) {
2632 q = strstr(buffer2,"Vendor: ");
2633 if (q) {
2634 q += 8;
2635 vendor = q;
2636 q = strstr(q," ");
2637 *q++ = 0; /* truncate vendor name */
2638 q = strstr(q,"Model: ");
2639 if (q) {
2640 *q = 0;
2641 q += 7;
2642 model = q;
2643 q = strstr(q," Rev: ");
2644 if (q) {
2645 *q = 0;
2646 for (i = 0; i < SIZE(sun_drives); i++) {
2647 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2648 continue;
2649 if (!strstr(model, sun_drives[i].model))
2650 continue;
2651 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2652 p = sun_drives + i;
2653 break;
2654 }
2655 }
2656 }
2657 }
2658 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002659 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002660 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002661 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002662 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002663 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002664 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002665#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002666 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002667}
2668
Rob Landleyb73451d2006-02-24 16:29:00 +00002669static void
2670create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002671{
2672 struct hd_geometry geometry;
2673 unsigned int ndiv;
2674 int i;
2675 unsigned char c;
2676 const struct sun_predefined_drives *p = NULL;
2677
2678 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002679 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2680 "until you decide to write them. After that, of course, the previous\n"
2681 "content won't be recoverable.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002682#if BYTE_ORDER == LITTLE_ENDIAN
2683 sun_other_endian = 1;
2684#else
2685 sun_other_endian = 0;
2686#endif
2687 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 */
5080 int i, readed = 0;
5081 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;
5129 if (start >= temp+units_per_sector && readed) {
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;
5132 readed = 0;
5133 }
5134 if (!readed && 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 }
5144 readed = 1;
5145 }
5146 } while (start != temp || !readed);
5147 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}