blob: a64515598bb91e33fc1c00c1de13c4cc61fdbdee [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_SUN_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000119static int sun_label; /* looking at sun disklabel */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000120#else
121#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000122#endif
123#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000124static int sgi_label; /* looking at sgi disklabel */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000125#else
126#define sgi_label 0
127#endif
128#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000129static int aix_label; /* looking at aix disklabel */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000130#else
131#define aix_label 0
132#endif
133#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000134static int osf_label; /* looking at OSF/1 disklabel */
135static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000136#else
137#define osf_label 0
138#endif
139
140#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
141
142static uint heads, sectors, cylinders;
143static void update_units(void);
144
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000145
146/*
147 * return partition name - uses static storage unless buf is supplied
148 */
149static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000150partname(const char *dev, int pno, int lth)
151{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000152 static char buffer[80];
153 const char *p;
154 int w, wp;
155 int bufsiz;
156 char *bufp;
157
158 bufp = buffer;
159 bufsiz = sizeof(buffer);
160
161 w = strlen(dev);
162 p = "";
163
164 if (isdigit(dev[w-1]))
165 p = "p";
166
167 /* devfs kludge - note: fdisk partition names are not supposed
168 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000169 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000170 w -= 4;
171 p = "part";
172 }
173
174 wp = strlen(p);
175
176 if (lth) {
177 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
178 lth-wp-2, w, dev, p, pno);
179 } else {
180 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
181 }
182 return bufp;
183}
184
185struct partition {
186 unsigned char boot_ind; /* 0x80 - active */
187 unsigned char head; /* starting head */
188 unsigned char sector; /* starting sector */
189 unsigned char cyl; /* starting cylinder */
190 unsigned char sys_ind; /* What partition type */
191 unsigned char end_head; /* end head */
192 unsigned char end_sector; /* end sector */
193 unsigned char end_cyl; /* end cylinder */
194 unsigned char start4[4]; /* starting sector counting from 0 */
195 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000196} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000197
198enum failure {
199 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
200 unable_to_write
201};
202
Rob Landleyb73451d2006-02-24 16:29:00 +0000203enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000204
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000205static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000206static int fd; /* the disk */
207static int partitions = 4; /* maximum partition + 1 */
208static uint display_in_cyl_units = 1;
209static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000210#ifdef CONFIG_FEATURE_FDISK_WRITABLE
211static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000212static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000213static void reread_partition_table(int leave);
214static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000215static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000216static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000217static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000218#endif
219static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000220static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000221static void get_geometry(void);
222static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000223
224#define PLURAL 0
225#define SINGULAR 1
226
227#define hex_val(c) ({ \
228 char _c = (c); \
229 isdigit(_c) ? _c - '0' : \
230 tolower(_c) + 10 - 'a'; \
231 })
232
233
234#define LINE_LENGTH 800
235#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
236 (n) * sizeof(struct partition)))
237#define sector(s) ((s) & 0x3f)
238#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
239
240#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
241 ((h) + heads * cylinder(s,c)))
242#define set_hsc(h,s,c,sector) { \
243 s = sector % sectors + 1; \
244 sector /= sectors; \
245 h = sector % heads; \
246 sector /= heads; \
247 c = sector & 0xff; \
248 s |= (sector >> 2) & 0xc0; \
249 }
250
251
Eric Andersend9261492004-06-28 23:50:31 +0000252static int32_t get_start_sect(const struct partition *p);
253static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000254
255/*
256 * per partition table entry data
257 *
258 * The four primary partitions have the same sectorbuffer (MBRbuffer)
259 * and have NULL ext_pointer.
260 * Each logical partition table entry has two pointers, one for the
261 * partition and one link to the next one.
262 */
263static struct pte {
264 struct partition *part_table; /* points into sectorbuffer */
265 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000266#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000267 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000268#endif
Eric Andersend9261492004-06-28 23:50:31 +0000269 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000270 char *sectorbuffer; /* disk sector contents */
271} ptes[MAXIMUM_PARTS];
272
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000273
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000274#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000275static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000276set_all_unchanged(void)
277{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000278 int i;
279
280 for (i = 0; i < MAXIMUM_PARTS; i++)
281 ptes[i].changed = 0;
282}
283
284static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000285set_changed(int i)
286{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000287 ptes[i].changed = 1;
288}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000289#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000290
291#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
292static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000293get_part_table(int i)
294{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000295 return ptes[i].part_table;
296}
297#endif
298
299static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000300str_units(int n)
301{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000302 if (n == 1)
303 return display_in_cyl_units ? _("cylinder") : _("sector");
304 else
305 return display_in_cyl_units ? _("cylinders") : _("sectors");
306}
307
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000308static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000309valid_part_table_flag(const char *mbuffer) {
310 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000311 return (b[510] == 0x55 && b[511] == 0xaa);
312}
313
314#ifdef CONFIG_FEATURE_FDISK_WRITABLE
315static char line_buffer[LINE_LENGTH];
316
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000317/* read line; return 0 or first char */
318static int
319read_line(void)
320{
321 static int got_eof = 0;
322
323 fflush (stdout); /* requested by niles@scyld.com */
324 line_ptr = line_buffer;
325 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
326 if (feof(stdin))
327 got_eof++; /* user typed ^D ? */
328 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000329 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
330 exit(1);
331 }
332 return 0;
333 }
334 while (*line_ptr && !isgraph(*line_ptr))
335 line_ptr++;
336 return *line_ptr;
337}
338
339static char
340read_char(const char *mesg)
341{
342 do {
343 fputs(mesg, stdout);
344 } while (!read_line());
345 return *line_ptr;
346}
347
348static char
349read_chars(const char *mesg)
350{
351 fputs(mesg, stdout);
352 if (!read_line()) {
353 *line_ptr = '\n';
354 line_ptr[1] = 0;
355 }
356 return *line_ptr;
357}
358
359static int
360read_hex(const struct systypes *sys)
361{
362 int hex;
363
Rob Landleyb73451d2006-02-24 16:29:00 +0000364 while (1) {
365 read_char(_("Hex code (type L to list codes): "));
366 if (*line_ptr == 'l' || *line_ptr == 'L')
367 list_types(sys);
368 else if (isxdigit (*line_ptr)) {
369 hex = 0;
370 do
371 hex = hex << 4 | hex_val(*line_ptr++);
372 while (isxdigit(*line_ptr));
373 return hex;
374 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000375 }
376}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000377#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000378
379#ifdef CONFIG_FEATURE_AIX_LABEL
380/*
381 * Copyright (C) Andreas Neuper, Sep 1998.
382 * This file may be redistributed under
383 * the terms of the GNU Public License.
384 */
385
386typedef struct {
387 unsigned int magic; /* expect AIX_LABEL_MAGIC */
388 unsigned int fillbytes1[124];
389 unsigned int physical_volume_id;
390 unsigned int fillbytes2[124];
391} aix_partition;
392
393#define AIX_LABEL_MAGIC 0xc9c2d4c1
394#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
395#define AIX_INFO_MAGIC 0x00072959
396#define AIX_INFO_MAGIC_SWAPPED 0x59290700
397
398#define aixlabel ((aix_partition *)MBRbuffer)
399
400
401/*
402 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000403 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
404 * Internationalization
405 *
406 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
407 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000408*/
409
Rob Landleyb73451d2006-02-24 16:29:00 +0000410static int aix_other_endian;
411static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000412
413/*
414 * only dealing with free blocks here
415 */
416
417static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000418aix_info(void)
419{
420 puts(
421 _("\n\tThere is a valid AIX label on this disk.\n"
422 "\tUnfortunately Linux cannot handle these\n"
423 "\tdisks at the moment. Nevertheless some\n"
424 "\tadvice:\n"
425 "\t1. fdisk will destroy its contents on write.\n"
426 "\t2. Be sure that this disk is NOT a still vital\n"
427 "\t part of a volume group. (Otherwise you may\n"
428 "\t erase the other disks as well, if unmirrored.)\n"
429 "\t3. Before deleting this physical volume be sure\n"
430 "\t to remove the disk logically from your AIX\n"
431 "\t machine. (Otherwise you become an AIXpert).")
432 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000433}
434
435static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000436aix_nolabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000437{
Rob Landleyb73451d2006-02-24 16:29:00 +0000438 aixlabel->magic = 0;
439 aix_label = 0;
440 partitions = 4;
441 memset(MBRbuffer, 0, sizeof(MBRbuffer)); /* avoid fdisk cores */
442 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000443}
444
445static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000446check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000447{
Rob Landleyb73451d2006-02-24 16:29:00 +0000448 if (aixlabel->magic != AIX_LABEL_MAGIC &&
449 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
450 aix_label = 0;
451 aix_other_endian = 0;
452 return 0;
453 }
454 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
455 update_units();
456 aix_label = 1;
457 partitions = 1016;
458 aix_volumes = 15;
459 aix_info();
460 aix_nolabel(); /* %% */
461 aix_label = 1; /* %% */
462 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000463}
464#endif /* AIX_LABEL */
465
466#ifdef CONFIG_FEATURE_OSF_LABEL
467/*
468 * Copyright (c) 1987, 1988 Regents of the University of California.
469 * All rights reserved.
470 *
471 * Redistribution and use in source and binary forms, with or without
472 * modification, are permitted provided that the following conditions
473 * are met:
474 * 1. Redistributions of source code must retain the above copyright
475 * notice, this list of conditions and the following disclaimer.
476 * 2. Redistributions in binary form must reproduce the above copyright
477 * notice, this list of conditions and the following disclaimer in the
478 * documentation and/or other materials provided with the distribution.
479 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000480 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000481 * This product includes software developed by the University of
482 * California, Berkeley and its contributors.
483 * 4. Neither the name of the University nor the names of its contributors
484 * may be used to endorse or promote products derived from this software
485 * without specific prior written permission.
486 *
487 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
488 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
489 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
490 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
491 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
492 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
493 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
494 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
495 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
496 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
497 * SUCH DAMAGE.
498 */
499
500
501#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000502#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000503#endif
504
505#ifndef BSD_MAXPARTITIONS
506#define BSD_MAXPARTITIONS 16
507#endif
508
509#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
510
511#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
512#define BSD_LABELSECTOR 1
513#define BSD_LABELOFFSET 0
514#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
515#define BSD_LABELSECTOR 0
516#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000517#elif defined (__s390__) || defined (__s390x__)
518#define BSD_LABELSECTOR 1
519#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000520#else
521#error unknown architecture
522#endif
523
524#define BSD_BBSIZE 8192 /* size of boot area, with label */
525#define BSD_SBSIZE 8192 /* max size of fs superblock */
526
527struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000528 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000529 int16_t d_type; /* drive type */
530 int16_t d_subtype; /* controller/d_type specific */
531 char d_typename[16]; /* type name, e.g. "eagle" */
532 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000533 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000534 uint32_t d_secsize; /* # of bytes per sector */
535 uint32_t d_nsectors; /* # of data sectors per track */
536 uint32_t d_ntracks; /* # of tracks per cylinder */
537 uint32_t d_ncylinders; /* # of data cylinders per unit */
538 uint32_t d_secpercyl; /* # of data sectors per cylinder */
539 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000540 /*
541 * Spares (bad sector replacements) below
542 * are not counted in d_nsectors or d_secpercyl.
543 * Spare sectors are assumed to be physical sectors
544 * which occupy space at the end of each track and/or cylinder.
545 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000546 uint16_t d_sparespertrack; /* # of spare sectors per track */
547 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000548 /*
549 * Alternate cylinders include maintenance, replacement,
550 * configuration description areas, etc.
551 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000552 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000553
554 /* hardware characteristics: */
555 /*
556 * d_interleave, d_trackskew and d_cylskew describe perturbations
557 * in the media format used to compensate for a slow controller.
558 * Interleave is physical sector interleave, set up by the formatter
559 * or controller when formatting. When interleaving is in use,
560 * logically adjacent sectors are not physically contiguous,
561 * but instead are separated by some number of sectors.
562 * It is specified as the ratio of physical sectors traversed
563 * per logical sector. Thus an interleave of 1:1 implies contiguous
564 * layout, while 2:1 implies that logical sector 0 is separated
565 * by one sector from logical sector 1.
566 * d_trackskew is the offset of sector 0 on track N
567 * relative to sector 0 on track N-1 on the same cylinder.
568 * Finally, d_cylskew is the offset of sector 0 on cylinder N
569 * relative to sector 0 on cylinder N-1.
570 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000571 uint16_t d_rpm; /* rotational speed */
572 uint16_t d_interleave; /* hardware sector interleave */
573 uint16_t d_trackskew; /* sector 0 skew, per track */
574 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
575 uint32_t d_headswitch; /* head switch time, usec */
576 uint32_t d_trkseek; /* track-to-track seek, usec */
577 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000578#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000579 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000580#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000581 uint32_t d_spare[NSPARE]; /* reserved for future use */
582 uint32_t d_magic2; /* the magic number (again) */
583 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000584 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000585 uint16_t d_npartitions; /* number of partitions in following */
586 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
587 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000588 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000589 uint32_t p_size; /* number of sectors in partition */
590 uint32_t p_offset; /* starting sector */
591 uint32_t p_fsize; /* filesystem basic fragment size */
592 uint8_t p_fstype; /* filesystem type, see below */
593 uint8_t p_frag; /* filesystem fragments per block */
594 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000595 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
596};
597
598/* d_type values: */
599#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
600#define BSD_DTYPE_MSCP 2 /* MSCP */
601#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
602#define BSD_DTYPE_SCSI 4 /* SCSI */
603#define BSD_DTYPE_ESDI 5 /* ESDI interface */
604#define BSD_DTYPE_ST506 6 /* ST506 etc. */
605#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
606#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
607#define BSD_DTYPE_FLOPPY 10 /* floppy */
608
609/* d_subtype values: */
610#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
611#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
612#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
613
614#ifdef DKTYPENAMES
615static const char * const xbsd_dktypenames[] = {
616 "unknown",
617 "SMD",
618 "MSCP",
619 "old DEC",
620 "SCSI",
621 "ESDI",
622 "ST506",
623 "HP-IB",
624 "HP-FL",
625 "type 9",
626 "floppy",
627 0
628};
629#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
630#endif
631
632/*
633 * Filesystem type and version.
634 * Used to interpret other filesystem-specific
635 * per-partition information.
636 */
637#define BSD_FS_UNUSED 0 /* unused */
638#define BSD_FS_SWAP 1 /* swap */
639#define BSD_FS_V6 2 /* Sixth Edition */
640#define BSD_FS_V7 3 /* Seventh Edition */
641#define BSD_FS_SYSV 4 /* System V */
642#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
643#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
644#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
645#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
646#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
647#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
648#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
649#define BSD_FS_ISOFS BSD_FS_ISO9660
650#define BSD_FS_BOOT 13 /* partition contains bootstrap */
651#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
652#define BSD_FS_HFS 15 /* Macintosh HFS */
653#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
654
655/* this is annoying, but it's also the way it is :-( */
656#ifdef __alpha__
657#define BSD_FS_EXT2 8 /* ext2 file system */
658#else
659#define BSD_FS_MSDOS 8 /* MS-DOS file system */
660#endif
661
662#ifdef DKTYPENAMES
663static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000664 { "\x00" "unused" }, /* BSD_FS_UNUSED */
665 { "\x01" "swap" }, /* BSD_FS_SWAP */
666 { "\x02" "Version 6" }, /* BSD_FS_V6 */
667 { "\x03" "Version 7" }, /* BSD_FS_V7 */
668 { "\x04" "System V" }, /* BSD_FS_SYSV */
669 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
670 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
671 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000672#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000673 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000674#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000675 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000676#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000677 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
678 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
679 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
680 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
681 { "\x0d" "boot" }, /* BSD_FS_BOOT */
682 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
683 { "\x0f" "HFS" }, /* BSD_FS_HFS */
684 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
685 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000686};
687#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
688
689#endif
690
691/*
692 * flags shared by various drives:
693 */
694#define BSD_D_REMOVABLE 0x01 /* removable media */
695#define BSD_D_ECC 0x02 /* supports ECC */
696#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
697#define BSD_D_RAMDISK 0x08 /* disk emulator */
698#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
699#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
700
701#endif /* OSF_LABEL */
702
703/*
704 * Copyright (C) Andreas Neuper, Sep 1998.
705 * This file may be modified and redistributed under
706 * the terms of the GNU Public License.
707 */
708
709struct device_parameter { /* 48 bytes */
710 unsigned char skew;
711 unsigned char gap1;
712 unsigned char gap2;
713 unsigned char sparecyl;
714 unsigned short pcylcount;
715 unsigned short head_vol0;
716 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
717 unsigned char cmd_tag_queue_depth;
718 unsigned char unused0;
719 unsigned short unused1;
720 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
721 unsigned short bytes;
722 unsigned short ilfact;
723 unsigned int flags; /* controller flags */
724 unsigned int datarate;
725 unsigned int retries_on_error;
726 unsigned int ms_per_word;
727 unsigned short xylogics_gap1;
728 unsigned short xylogics_syncdelay;
729 unsigned short xylogics_readdelay;
730 unsigned short xylogics_gap2;
731 unsigned short xylogics_readgate;
732 unsigned short xylogics_writecont;
733};
734
735#define SGI_VOLHDR 0x00
736/* 1 and 2 were used for drive types no longer supported by SGI */
737#define SGI_SWAP 0x03
738/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
739#define SGI_VOLUME 0x06
740#define SGI_EFS 0x07
741#define SGI_LVOL 0x08
742#define SGI_RLVOL 0x09
743#define SGI_XFS 0x0a
744#define SGI_XFSLOG 0x0b
745#define SGI_XLV 0x0c
746#define SGI_XVM 0x0d
747#define ENTIRE_DISK SGI_VOLUME
748/*
749 * controller flags
750 */
751#define SECTOR_SLIP 0x01
752#define SECTOR_FWD 0x02
753#define TRACK_FWD 0x04
754#define TRACK_MULTIVOL 0x08
755#define IGNORE_ERRORS 0x10
756#define RESEEK 0x20
757#define ENABLE_CMDTAGQ 0x40
758
759typedef struct {
760 unsigned int magic; /* expect SGI_LABEL_MAGIC */
761 unsigned short boot_part; /* active boot partition */
762 unsigned short swap_part; /* active swap partition */
763 unsigned char boot_file[16]; /* name of the bootfile */
764 struct device_parameter devparam; /* 1 * 48 bytes */
765 struct volume_directory { /* 15 * 16 bytes */
766 unsigned char vol_file_name[8]; /* a character array */
767 unsigned int vol_file_start; /* number of logical block */
768 unsigned int vol_file_size; /* number of bytes */
769 } directory[15];
770 struct sgi_partition { /* 16 * 12 bytes */
771 unsigned int num_sectors; /* number of blocks */
772 unsigned int start_sector; /* must be cylinder aligned */
773 unsigned int id;
774 } partitions[16];
775 unsigned int csum;
776 unsigned int fillbytes;
777} sgi_partition;
778
779typedef struct {
780 unsigned int magic; /* looks like a magic number */
781 unsigned int a2;
782 unsigned int a3;
783 unsigned int a4;
784 unsigned int b1;
785 unsigned short b2;
786 unsigned short b3;
787 unsigned int c[16];
788 unsigned short d[3];
789 unsigned char scsi_string[50];
790 unsigned char serial[137];
791 unsigned short check1816;
792 unsigned char installer[225];
793} sgiinfo;
794
795#define SGI_LABEL_MAGIC 0x0be5a941
796#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
797#define SGI_INFO_MAGIC 0x00072959
798#define SGI_INFO_MAGIC_SWAPPED 0x59290700
799#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000800 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000801#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000802 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000803
804#define sgilabel ((sgi_partition *)MBRbuffer)
805#define sgiparam (sgilabel->devparam)
806
807typedef struct {
808 unsigned char info[128]; /* Informative text string */
809 unsigned char spare0[14];
810 struct sun_info {
811 unsigned char spare1;
812 unsigned char id;
813 unsigned char spare2;
814 unsigned char flags;
815 } infos[8];
816 unsigned char spare1[246]; /* Boot information etc. */
817 unsigned short rspeed; /* Disk rotational speed */
818 unsigned short pcylcount; /* Physical cylinder count */
819 unsigned short sparecyl; /* extra sects per cylinder */
820 unsigned char spare2[4]; /* More magic... */
821 unsigned short ilfact; /* Interleave factor */
822 unsigned short ncyl; /* Data cylinder count */
823 unsigned short nacyl; /* Alt. cylinder count */
824 unsigned short ntrks; /* Tracks per cylinder */
825 unsigned short nsect; /* Sectors per track */
826 unsigned char spare3[4]; /* Even more magic... */
827 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000828 uint32_t start_cylinder;
829 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000830 } partitions[8];
831 unsigned short magic; /* Magic number */
832 unsigned short csum; /* Label xor'd checksum */
833} sun_partition;
834
Eric Andersen040f4402003-07-30 08:40:37 +0000835
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000836#define SUN_LABEL_MAGIC 0xDABE
837#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
838#define sunlabel ((sun_partition *)MBRbuffer)
839#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000840 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000841#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000842 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000843
Eric Andersend3652bf2003-08-06 09:07:37 +0000844
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000845#ifdef CONFIG_FEATURE_OSF_LABEL
846/*
847 Changes:
848 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
849
850 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
851 support for OSF/1 disklabels on Alpha.
852 Also fixed unaligned accesses in alpha_bootblock_checksum()
853*/
854
855#define FREEBSD_PARTITION 0xa5
856#define NETBSD_PARTITION 0xa9
857
Rob Landleyb73451d2006-02-24 16:29:00 +0000858static void xbsd_delete_part(void);
859static void xbsd_new_part(void);
860static void xbsd_write_disklabel(void);
861static int xbsd_create_disklabel(void);
862static void xbsd_edit_disklabel(void);
863static void xbsd_write_bootstrap(void);
864static void xbsd_change_fstype(void);
865static int xbsd_get_part_index(int max);
866static int xbsd_check_new_partition(int *i);
867static void xbsd_list_types(void);
868static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
869static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
870static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
871static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000872
873#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000874static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000875#endif
876
877#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000878static int xbsd_translate_fstype(int linux_type);
879static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000880static struct partition *xbsd_part;
881static int xbsd_part_index;
882#endif
883
884#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000885/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000886static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000887#else
888static char disklabelbuffer[BSD_BBSIZE];
889#endif
890
891static struct xbsd_disklabel xbsd_dlabel;
892
893#define bsd_cround(n) \
894 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
895
896/*
897 * Test whether the whole disk has BSD disk label magic.
898 *
899 * Note: often reformatting with DOS-type label leaves the BSD magic,
900 * so this does not mean that there is a BSD disk label.
901 */
902static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000903check_osf_label(void)
904{
905 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000906 return 0;
907 return 1;
908}
909
910static void xbsd_print_disklabel(int);
911
912static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000913btrydev(const char * dev)
914{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000915 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
916 return -1;
917 printf(_("\nBSD label for device: %s\n"), dev);
918 xbsd_print_disklabel (0);
919 return 0;
920}
921
922static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000923bmenu(void)
924{
925 puts (_("Command action"));
926 puts (_("\td\tdelete a BSD partition"));
927 puts (_("\te\tedit drive data"));
928 puts (_("\ti\tinstall bootstrap"));
929 puts (_("\tl\tlist known filesystem types"));
930 puts (_("\tm\tprint this menu"));
931 puts (_("\tn\tadd a new BSD partition"));
932 puts (_("\tp\tprint BSD partition table"));
933 puts (_("\tq\tquit without saving changes"));
934 puts (_("\tr\treturn to main menu"));
935 puts (_("\ts\tshow complete disklabel"));
936 puts (_("\tt\tchange a partition's filesystem id"));
937 puts (_("\tu\tchange units (cylinders/sectors)"));
938 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000939#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000940 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000941#endif
942}
943
944#if !defined (__alpha__)
945static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000946hidden(int type)
947{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000948 return type ^ 0x10;
949}
950
951static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000952is_bsd_partition_type(int type)
953{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000954 return (type == FREEBSD_PARTITION ||
955 type == hidden(FREEBSD_PARTITION) ||
956 type == NETBSD_PARTITION ||
957 type == hidden(NETBSD_PARTITION));
958}
959#endif
960
961static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000962bselect(void)
963{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000964#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000965 int t, ss;
966 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000967
Rob Landleyb73451d2006-02-24 16:29:00 +0000968 for (t = 0; t < 4; t++) {
969 p = get_part_table(t);
970 if (p && is_bsd_partition_type(p->sys_ind)) {
971 xbsd_part = p;
972 xbsd_part_index = t;
973 ss = get_start_sect(xbsd_part);
974 if (ss == 0) {
975 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
976 partname(disk_device, t+1, 0));
977 return;
978 }
979 printf(_("Reading disklabel of %s at sector %d.\n"),
980 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
981 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
982 if (xbsd_create_disklabel() == 0)
983 return;
984 break;
985 }
986 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000987
Rob Landleyb73451d2006-02-24 16:29:00 +0000988 if (t == 4) {
989 printf(_("There is no *BSD partition on %s.\n"), disk_device);
990 return;
991 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000992
993#elif defined (__alpha__)
994
Rob Landleyb73451d2006-02-24 16:29:00 +0000995 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
996 if (xbsd_create_disklabel() == 0)
997 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000998
999#endif
1000
Rob Landleyb73451d2006-02-24 16:29:00 +00001001 while (1) {
1002 putchar('\n');
1003 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
1004 case 'd':
1005 xbsd_delete_part();
1006 break;
1007 case 'e':
1008 xbsd_edit_disklabel();
1009 break;
1010 case 'i':
1011 xbsd_write_bootstrap();
1012 break;
1013 case 'l':
1014 xbsd_list_types();
1015 break;
1016 case 'n':
1017 xbsd_new_part();
1018 break;
1019 case 'p':
1020 xbsd_print_disklabel(0);
1021 break;
1022 case 'q':
1023 close(fd);
1024 exit(EXIT_SUCCESS);
1025 case 'r':
1026 return;
1027 case 's':
1028 xbsd_print_disklabel(1);
1029 break;
1030 case 't':
1031 xbsd_change_fstype();
1032 break;
1033 case 'u':
1034 change_units();
1035 break;
1036 case 'w':
1037 xbsd_write_disklabel();
1038 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001039#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001040 case 'x':
1041 xbsd_link_part();
1042 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001043#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001044 default:
1045 bmenu();
1046 break;
1047 }
1048 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001049}
1050
1051static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001052xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001053{
Rob Landleyb73451d2006-02-24 16:29:00 +00001054 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001055
Rob Landleyb73451d2006-02-24 16:29:00 +00001056 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1057 xbsd_dlabel.d_partitions[i].p_size = 0;
1058 xbsd_dlabel.d_partitions[i].p_offset = 0;
1059 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1060 if (xbsd_dlabel.d_npartitions == i + 1)
1061 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1062 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001063}
1064
1065static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001066xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001067{
Rob Landleyb73451d2006-02-24 16:29:00 +00001068 off_t begin, end;
1069 char mesg[256];
1070 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001071
Rob Landleyb73451d2006-02-24 16:29:00 +00001072 if (!xbsd_check_new_partition(&i))
1073 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001074
1075#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001076 begin = get_start_sect(xbsd_part);
1077 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001078#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001079 begin = 0;
1080 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001081#endif
1082
Rob Landleyb73451d2006-02-24 16:29:00 +00001083 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1084 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1085 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001086
Rob Landleyb73451d2006-02-24 16:29:00 +00001087 if (display_in_cyl_units)
1088 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001089
Rob Landleyb73451d2006-02-24 16:29:00 +00001090 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1091 str_units(SINGULAR));
1092 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1093 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001094
Rob Landleyb73451d2006-02-24 16:29:00 +00001095 if (display_in_cyl_units)
1096 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001097
Rob Landleyb73451d2006-02-24 16:29:00 +00001098 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1099 xbsd_dlabel.d_partitions[i].p_offset = begin;
1100 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001101}
1102
1103static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001104xbsd_print_disklabel(int show_all)
1105{
1106 struct xbsd_disklabel *lp = &xbsd_dlabel;
1107 struct xbsd_partition *pp;
1108 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001109
Rob Landleyb73451d2006-02-24 16:29:00 +00001110 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001111#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001112 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001113#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001114 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001115#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001116 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1117 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1118 else
1119 printf(_("type: %d\n"), lp->d_type);
1120 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1121 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1122 printf(_("flags:"));
1123 if (lp->d_flags & BSD_D_REMOVABLE)
1124 printf(_(" removable"));
1125 if (lp->d_flags & BSD_D_ECC)
1126 printf(_(" ecc"));
1127 if (lp->d_flags & BSD_D_BADSECT)
1128 printf(_(" badsect"));
1129 printf("\n");
1130 /* On various machines the fields of *lp are short/int/long */
1131 /* In order to avoid problems, we cast them all to long. */
1132 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1133 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1134 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1135 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1136 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1137 printf(_("rpm: %d\n"), lp->d_rpm);
1138 printf(_("interleave: %d\n"), lp->d_interleave);
1139 printf(_("trackskew: %d\n"), lp->d_trackskew);
1140 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1141 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1142 (long) lp->d_headswitch);
1143 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1144 (long) lp->d_trkseek);
1145 printf(_("drivedata: "));
1146 for (i = NDDATA - 1; i >= 0; i--)
1147 if (lp->d_drivedata[i])
1148 break;
1149 if (i < 0)
1150 i = 0;
1151 for (j = 0; j <= i; j++)
1152 printf("%ld ", (long) lp->d_drivedata[j]);
1153 }
1154 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1155 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1156 pp = lp->d_partitions;
1157 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1158 if (pp->p_size) {
1159 if (display_in_cyl_units && lp->d_secpercyl) {
1160 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1161 'a' + i,
1162 (long) pp->p_offset / lp->d_secpercyl + 1,
1163 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1164 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1165 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1166 (long) pp->p_size / lp->d_secpercyl,
1167 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1168 );
1169 } else {
1170 printf(" %c: %8ld %8ld %8ld ",
1171 'a' + i,
1172 (long) pp->p_offset,
1173 (long) pp->p_offset + pp->p_size - 1,
1174 (long) pp->p_size
1175 );
1176 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001177
Rob Landleyb73451d2006-02-24 16:29:00 +00001178 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1179 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1180 else
1181 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001182
Rob Landleyb73451d2006-02-24 16:29:00 +00001183 switch (pp->p_fstype) {
1184 case BSD_FS_UNUSED:
1185 printf(" %5ld %5ld %5.5s ",
1186 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1187 break;
1188 case BSD_FS_BSDFFS:
1189 printf(" %5ld %5ld %5d ",
1190 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1191 break;
1192 default:
1193 printf("%22.22s", "");
1194 break;
1195 }
1196 printf("\n");
1197 }
1198 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001199}
1200
1201static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001202xbsd_write_disklabel(void)
1203{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001204#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001205 printf(_("Writing disklabel to %s.\n"), disk_device);
1206 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001207#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001208 printf(_("Writing disklabel to %s.\n"),
1209 partname(disk_device, xbsd_part_index + 1, 0));
1210 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001211#endif
1212 reread_partition_table(0); /* no exit yet */
1213}
1214
1215static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001216xbsd_create_disklabel(void)
1217{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001218 char c;
1219
1220#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001221 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001222#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001223 fprintf(stderr, _("%s contains no disklabel.\n"),
1224 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001225#endif
1226
1227 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001228 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001229 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001230 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001231#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001232 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001233 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001234#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001235 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001236#endif
1237 ) == 1) {
1238 xbsd_print_disklabel (1);
1239 return 1;
1240 } else
1241 return 0;
1242 } else if (c == 'n')
1243 return 0;
1244 }
1245}
1246
1247static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001248edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001249{
Rob Landleyb73451d2006-02-24 16:29:00 +00001250 do {
1251 fputs(mesg, stdout);
1252 printf(" (%d): ", def);
1253 if (!read_line())
1254 return def;
1255 }
1256 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1257 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001258}
1259
1260static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001261xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001262{
Rob Landleyb73451d2006-02-24 16:29:00 +00001263 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001264
Rob Landleyb73451d2006-02-24 16:29:00 +00001265 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001266
1267#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001268 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1269 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1270 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1271 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001272#endif
1273
Rob Landleyb73451d2006-02-24 16:29:00 +00001274 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1275 while (1) {
1276 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1277 _("sectors/cylinder"));
1278 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1279 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001280
Rob Landleyb73451d2006-02-24 16:29:00 +00001281 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1282 }
1283 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1284 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1285 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1286 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1287 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1288 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001289
Rob Landleyb73451d2006-02-24 16:29:00 +00001290 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291}
1292
1293static int
1294xbsd_get_bootstrap (char *path, void *ptr, int size)
1295{
Rob Landleyb73451d2006-02-24 16:29:00 +00001296 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001297
Rob Landleyb73451d2006-02-24 16:29:00 +00001298 if ((fdb = open (path, O_RDONLY)) < 0) {
1299 perror(path);
1300 return 0;
1301 }
1302 if (read(fdb, ptr, size) < 0) {
1303 perror(path);
1304 close(fdb);
1305 return 0;
1306 }
1307 printf(" ... %s\n", path);
1308 close(fdb);
1309 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001310}
1311
1312static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001313sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001314{
Rob Landleyb73451d2006-02-24 16:29:00 +00001315 printf(_("\nSyncing disks.\n"));
1316 sync();
1317 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001318}
1319
1320static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001321xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001322{
Rob Landleyb73451d2006-02-24 16:29:00 +00001323 char *bootdir = BSD_LINUX_BOOTDIR;
1324 char path[MAXPATHLEN];
1325 char *dkbasename;
1326 struct xbsd_disklabel dl;
1327 char *d, *p, *e;
1328 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001329
Rob Landleyb73451d2006-02-24 16:29:00 +00001330 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1331 dkbasename = "sd";
1332 else
1333 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001334
Rob Landleyb73451d2006-02-24 16:29:00 +00001335 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1336 dkbasename, dkbasename, dkbasename);
1337 if (read_line()) {
1338 line_ptr[strlen(line_ptr)-1] = '\0';
1339 dkbasename = line_ptr;
1340 }
1341 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1342 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1343 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001344
Rob Landleyb73451d2006-02-24 16:29:00 +00001345/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1346 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1347 bcopy(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001348
Rob Landleyb73451d2006-02-24 16:29:00 +00001349/* The disklabel will be overwritten by 0's from bootxx anyway */
1350 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001351
Rob Landleyb73451d2006-02-24 16:29:00 +00001352 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1353 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001354 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001355 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001356
Rob Landleyb73451d2006-02-24 16:29:00 +00001357 e = d + sizeof(struct xbsd_disklabel);
1358 for (p = d; p < e; p++)
1359 if (*p) {
1360 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1361 exit(EXIT_FAILURE);
1362 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001363
Rob Landleyb73451d2006-02-24 16:29:00 +00001364 bcopy(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001365
1366#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001367 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001368#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001369 sector = 0;
1370 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001371#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001372 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373#endif
1374
Rob Landleyb73451d2006-02-24 16:29:00 +00001375 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1376 fdisk_fatal(unable_to_seek);
1377 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1378 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001379
1380#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001381 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001382#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001383 printf(_("Bootstrap installed on %s.\n"),
1384 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001385#endif
1386
Rob Landleyb73451d2006-02-24 16:29:00 +00001387 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001388}
1389
1390static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001391xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001392{
Rob Landleyb73451d2006-02-24 16:29:00 +00001393 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001394
Rob Landleyb73451d2006-02-24 16:29:00 +00001395 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1396 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001397}
1398
1399static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001400xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001401{
Rob Landleyb73451d2006-02-24 16:29:00 +00001402 char prompt[256];
1403 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001404
Rob Landleyb73451d2006-02-24 16:29:00 +00001405 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1406 do
1407 l = tolower(read_char(prompt));
1408 while (l < 'a' || l > 'a' + max - 1);
1409 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001410}
1411
1412static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001413xbsd_check_new_partition(int *i)
1414{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001415 /* room for more? various BSD flavours have different maxima */
1416 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1417 int t;
1418
1419 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1420 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1421 break;
1422
1423 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001424 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001425 "has been created\n"));
1426 return 0;
1427 }
1428 }
1429
1430 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1431
1432 if (*i >= xbsd_dlabel.d_npartitions)
1433 xbsd_dlabel.d_npartitions = (*i) + 1;
1434
1435 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001436 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001437 return 0;
1438 }
1439
1440 return 1;
1441}
1442
1443static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001444xbsd_list_types(void)
1445{
1446 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001447}
1448
1449static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001450xbsd_dkcksum(struct xbsd_disklabel *lp)
1451{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001452 u_short *start, *end;
1453 u_short sum = 0;
1454
1455 start = (u_short *) lp;
1456 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1457 while (start < end)
1458 sum ^= *start++;
1459 return sum;
1460}
1461
1462static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001463xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1464{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001465 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001466
Rob Landleyb73451d2006-02-24 16:29:00 +00001467 get_geometry();
1468 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001469
Rob Landleyb73451d2006-02-24 16:29:00 +00001470 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001471
Rob Landleyb73451d2006-02-24 16:29:00 +00001472 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1473 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001474 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001475 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001476
1477#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001478 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001479#endif
1480
1481#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001482 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001483#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001484 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001485#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001486 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1487 d->d_nsectors = sectors; /* sectors/track */
1488 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1489 d->d_ncylinders = cylinders;
1490 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1491 if (d->d_secpercyl == 0)
1492 d->d_secpercyl = 1; /* avoid segfaults */
1493 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001494
Rob Landleyb73451d2006-02-24 16:29:00 +00001495 d->d_rpm = 3600;
1496 d->d_interleave = 1;
1497 d->d_trackskew = 0;
1498 d->d_cylskew = 0;
1499 d->d_headswitch = 0;
1500 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001501
Rob Landleyb73451d2006-02-24 16:29:00 +00001502 d->d_magic2 = BSD_DISKMAGIC;
1503 d->d_bbsize = BSD_BBSIZE;
1504 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001505
1506#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001507 d->d_npartitions = 4;
1508 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001509 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001510 pp->p_offset = get_start_sect(p);
1511 pp->p_size = get_nr_sects(p);
1512 pp->p_fstype = BSD_FS_UNUSED;
1513 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001514 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001515 pp->p_offset = 0;
1516 pp->p_size = d->d_secperunit;
1517 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001518#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001519 d->d_npartitions = 3;
1520 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001521 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001522 pp->p_offset = 0;
1523 pp->p_size = d->d_secperunit;
1524 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001525#endif
1526
1527 return 1;
1528}
1529
1530/*
1531 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1532 * If it has the right magic, return 1.
1533 */
1534static int
1535xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1536{
1537 int t, sector;
1538
1539 /* p is used only to get the starting sector */
1540#if !defined (__alpha__)
1541 sector = (p ? get_start_sect(p) : 0);
1542#elif defined (__alpha__)
1543 sector = 0;
1544#endif
1545
Rob Landleyb73451d2006-02-24 16:29:00 +00001546 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1547 fdisk_fatal(unable_to_seek);
1548 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1549 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001550
Rob Landleyb73451d2006-02-24 16:29:00 +00001551 bcopy(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1552 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001553
Rob Landleyb73451d2006-02-24 16:29:00 +00001554 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001555 return 0;
1556
Rob Landleyb73451d2006-02-24 16:29:00 +00001557 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1558 d->d_partitions[t].p_size = 0;
1559 d->d_partitions[t].p_offset = 0;
1560 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001561 }
1562
Rob Landleyb73451d2006-02-24 16:29:00 +00001563 if (d->d_npartitions > BSD_MAXPARTITIONS)
1564 fprintf(stderr, _("Warning: too many partitions "
1565 "(%d, maximum is %d).\n"),
1566 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001567 return 1;
1568}
1569
1570static int
1571xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1572{
Rob Landleyb73451d2006-02-24 16:29:00 +00001573 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001574
1575#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001576 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001577#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001578 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001579#endif
1580
Rob Landleyb73451d2006-02-24 16:29:00 +00001581 d->d_checksum = 0;
1582 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001583
Rob Landleyb73451d2006-02-24 16:29:00 +00001584 /* This is necessary if we want to write the bootstrap later,
1585 otherwise we'd write the old disklabel with the bootstrap.
1586 */
1587 bcopy(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1588 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001589
1590#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001591 alpha_bootblock_checksum (disklabelbuffer);
1592 if (lseek(fd, 0, SEEK_SET) == -1)
1593 fdisk_fatal(unable_to_seek);
1594 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1595 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001596#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001597 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1598 fdisk_fatal(unable_to_seek);
1599 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1600 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001601#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001602 sync_disks();
1603 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001604}
1605
1606
1607#if !defined (__alpha__)
1608static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001609xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001610{
Rob Landleyb73451d2006-02-24 16:29:00 +00001611 switch (linux_type) {
1612 case 0x01: /* DOS 12-bit FAT */
1613 case 0x04: /* DOS 16-bit <32M */
1614 case 0x06: /* DOS 16-bit >=32M */
1615 case 0xe1: /* DOS access */
1616 case 0xe3: /* DOS R/O */
1617 case 0xf2: /* DOS secondary */
1618 return BSD_FS_MSDOS;
1619 case 0x07: /* OS/2 HPFS */
1620 return BSD_FS_HPFS;
1621 default:
1622 return BSD_FS_OTHER;
1623 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001624}
1625
1626static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001627xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001628{
Rob Landleyb73451d2006-02-24 16:29:00 +00001629 int k, i;
1630 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001631
Rob Landleyb73451d2006-02-24 16:29:00 +00001632 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001633
Rob Landleyb73451d2006-02-24 16:29:00 +00001634 if (!xbsd_check_new_partition(&i))
1635 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001636
Rob Landleyb73451d2006-02-24 16:29:00 +00001637 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001638
Rob Landleyb73451d2006-02-24 16:29:00 +00001639 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1640 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1641 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001642}
1643#endif
1644
1645#if defined (__alpha__)
1646
1647#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001648typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001649#endif
1650
1651static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001652alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001653{
Rob Landleyb73451d2006-02-24 16:29:00 +00001654 uint64_t *dp, sum;
1655 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001656
Rob Landleyb73451d2006-02-24 16:29:00 +00001657 dp = (uint64_t *)boot;
1658 sum = 0;
1659 for (i = 0; i < 63; i++)
1660 sum += dp[i];
1661 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001662}
1663#endif /* __alpha__ */
1664
1665#endif /* OSF_LABEL */
1666
1667#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1668static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001669__swap16(unsigned short x)
1670{
Eric Andersenacd244a2002-12-11 03:49:33 +00001671 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001672}
1673
Eric Andersenacd244a2002-12-11 03:49:33 +00001674static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001675__swap32(uint32_t x)
1676{
1677 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001678 ((x & 0xFF00) << 8) |
1679 ((x & 0xFF0000) >> 8) |
1680 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001681}
1682#endif
1683
1684#ifdef CONFIG_FEATURE_SGI_LABEL
1685/*
1686 *
1687 * fdisksgilabel.c
1688 *
1689 * Copyright (C) Andreas Neuper, Sep 1998.
1690 * This file may be modified and redistributed under
1691 * the terms of the GNU Public License.
1692 *
1693 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1694 * Internationalization
1695 */
1696
1697
Rob Landleyb73451d2006-02-24 16:29:00 +00001698static int sgi_other_endian;
1699static int debug;
1700static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001701
1702/*
1703 * only dealing with free blocks here
1704 */
1705
Rob Landleyb73451d2006-02-24 16:29:00 +00001706typedef struct {
1707 unsigned int first;
1708 unsigned int last;
1709} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001710static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1711
1712static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001713setfreelist(int i, unsigned int f, unsigned int l)
1714{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001715 freelist[i].first = f;
1716 freelist[i].last = l;
1717}
1718
1719static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001720add2freelist(unsigned int f, unsigned int l)
1721{
1722 int i;
1723 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001724 if (freelist[i].last == 0)
1725 break;
1726 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001727}
1728
1729static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001730clearfreelist(void)
1731{
Eric Andersen040f4402003-07-30 08:40:37 +00001732 int i;
1733
1734 for (i = 0; i < 17 ; i++)
1735 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001736}
1737
Eric Andersen040f4402003-07-30 08:40:37 +00001738static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001739isinfreelist(unsigned int b)
1740{
Eric Andersen040f4402003-07-30 08:40:37 +00001741 int i;
1742
1743 for (i = 0; i < 17 ; i++)
1744 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001745 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001746 return 0;
1747}
1748 /* return last vacant block of this stride (never 0). */
1749 /* the '>=' is not quite correct, but simplifies the code */
1750/*
1751 * end of free blocks section
1752 */
1753
1754static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001755/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1756/* 0x01 */ { "\x01" "SGI trkrepl" },
1757/* 0x02 */ { "\x02" "SGI secrepl" },
1758/* SGI_SWAP */ { "\x03" "SGI raw" },
1759/* 0x04 */ { "\x04" "SGI bsd" },
1760/* 0x05 */ { "\x05" "SGI sysv" },
1761/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1762/* SGI_EFS */ { "\x07" "SGI efs" },
1763/* 0x08 */ { "\x08" "SGI lvol" },
1764/* 0x09 */ { "\x09" "SGI rlvol" },
1765/* SGI_XFS */ { "\x0a" "SGI xfs" },
1766/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1767/* SGI_XLV */ { "\x0c" "SGI xlv" },
1768/* SGI_XVM */ { "\x0d" "SGI xvm" },
1769/* LINUX_SWAP */ { "\x82" "Linux swap" },
1770/* LINUX_NATIVE */ { "\x83" "Linux native" },
1771/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1772/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1773 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001774};
1775
1776
1777static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001778sgi_get_nsect(void)
1779{
1780 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001781}
1782
1783static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001784sgi_get_ntrks(void)
1785{
1786 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001787}
1788
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001789static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001790sgi_nolabel(void)
1791{
1792 sgilabel->magic = 0;
1793 sgi_label = 0;
1794 partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001795}
1796
1797static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001798two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1799{
1800 int i = 0;
1801 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001802
Rob Landleyb73451d2006-02-24 16:29:00 +00001803 size /= sizeof(unsigned int);
1804 for (i = 0; i < size; i++)
1805 sum -= SGI_SSWAP32(base[i]);
1806 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001807}
1808
1809static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001810check_sgi_label(void)
1811{
1812 if (sizeof(sgilabel) > 512) {
1813 fprintf(stderr,
1814 _("According to MIPS Computer Systems, Inc the "
1815 "Label must not contain more than 512 bytes\n"));
1816 exit(1);
1817 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001818
Rob Landleyb73451d2006-02-24 16:29:00 +00001819 if (sgilabel->magic != SGI_LABEL_MAGIC
1820 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1821 sgi_label = 0;
1822 sgi_other_endian = 0;
1823 return 0;
1824 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001825
Rob Landleyb73451d2006-02-24 16:29:00 +00001826 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1827 /*
1828 * test for correct checksum
1829 */
1830 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1831 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001832 fprintf(stderr,
1833 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001834 }
1835 update_units();
1836 sgi_label = 1;
1837 partitions = 16;
1838 sgi_volumes = 15;
1839 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001840}
1841
Eric Andersen040f4402003-07-30 08:40:37 +00001842static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001843sgi_get_start_sector(int i)
1844{
1845 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001846}
1847
Eric Andersen040f4402003-07-30 08:40:37 +00001848static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001849sgi_get_num_sectors(int i)
1850{
1851 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001852}
1853
1854static int
Eric Andersen040f4402003-07-30 08:40:37 +00001855sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001856{
Rob Landleyb73451d2006-02-24 16:29:00 +00001857 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001858}
1859
1860static int
1861sgi_get_bootpartition(void)
1862{
Rob Landleyb73451d2006-02-24 16:29:00 +00001863 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001864}
1865
1866static int
1867sgi_get_swappartition(void)
1868{
Rob Landleyb73451d2006-02-24 16:29:00 +00001869 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001870}
1871
1872static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001873sgi_list_table(int xtra)
1874{
1875 int i, w, wd;
1876 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001877
Rob Landleyb73451d2006-02-24 16:29:00 +00001878 if(xtra) {
1879 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1880 "%d cylinders, %d physical cylinders\n"
1881 "%d extra sects/cyl, interleave %d:1\n"
1882 "%s\n"
1883 "Units = %s of %d * 512 bytes\n\n"),
1884 disk_device, heads, sectors, cylinders,
1885 SGI_SSWAP16(sgiparam.pcylcount),
1886 SGI_SSWAP16(sgiparam.sparecyl),
1887 SGI_SSWAP16(sgiparam.ilfact),
1888 (char *)sgilabel,
1889 str_units(PLURAL), units_per_sector);
1890 } else {
1891 printf( _("\nDisk %s (SGI disk label): "
1892 "%d heads, %d sectors, %d cylinders\n"
1893 "Units = %s of %d * 512 bytes\n\n"),
1894 disk_device, heads, sectors, cylinders,
1895 str_units(PLURAL), units_per_sector );
1896 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001897
Rob Landleyb73451d2006-02-24 16:29:00 +00001898 w = strlen(disk_device);
1899 wd = strlen(_("Device"));
1900 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001901 w = wd;
1902
Rob Landleyb73451d2006-02-24 16:29:00 +00001903 printf(_("----- partitions -----\n"
1904 "Pt# %*s Info Start End Sectors Id System\n"),
1905 w + 2, _("Device"));
1906 for (i = 0 ; i < partitions; i++) {
1907 if( sgi_get_num_sectors(i) || debug ) {
1908 uint32_t start = sgi_get_start_sector(i);
1909 uint32_t len = sgi_get_num_sectors(i);
1910 kpi++; /* only count nonempty partitions */
1911 printf(
1912 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1913/* fdisk part number */ i+1,
1914/* device */ partname(disk_device, kpi, w+3),
1915/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1916/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1917/* start */ (long) scround(start),
1918/* end */ (long) scround(start+len)-1,
1919/* no odd flag on end */(long) len,
1920/* type id */ sgi_get_sysid(i),
1921/* type name */ partition_type(sgi_get_sysid(i)));
1922 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001923 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001924 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1925 "----- Directory Entries -----\n"),
1926 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001927 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001928 if (sgilabel->directory[i].vol_file_size) {
1929 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1930 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1931 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001932
Rob Landleyb73451d2006-02-24 16:29:00 +00001933 printf(_("%2d: %-10s sector%5u size%8u\n"),
1934 i, (char*)name, (unsigned int) start, (unsigned int) len);
1935 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001936 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001937}
1938
1939static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001940sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001941{
Rob Landleyb73451d2006-02-24 16:29:00 +00001942 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001943}
1944
Eric Andersen040f4402003-07-30 08:40:37 +00001945static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001946sgi_get_lastblock(void)
1947{
1948 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001949}
1950
1951static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001952sgi_set_swappartition(int i)
1953{
1954 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001955}
1956
1957static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001958sgi_check_bootfile(const char* aFile)
1959{
1960 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1961 printf(_("\nInvalid Bootfile!\n"
1962 "\tThe bootfile must be an absolute non-zero pathname,\n"
1963 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1964 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001965 } else {
1966 if (strlen(aFile) > 16) {
1967 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001968 "16 bytes maximum.\n"));
1969 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001970 } else {
1971 if (aFile[0] != '/') {
1972 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001973 "fully qualified pathname.\n"));
1974 return 0;
1975 }
Eric Andersen040f4402003-07-30 08:40:37 +00001976 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001977 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001978 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001979 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1980 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001981 /* filename is correct and did change */
1982 return 1;
1983 }
1984 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001985}
1986
1987static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001988sgi_get_bootfile(void)
1989{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001990 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001991}
1992
1993static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001994sgi_set_bootfile(const char* aFile)
1995{
1996 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001997
Rob Landleyb73451d2006-02-24 16:29:00 +00001998 if (sgi_check_bootfile(aFile)) {
1999 while (i < 16) {
2000 if ((aFile[i] != '\n') /* in principle caught again by next line */
2001 && (strlen(aFile) > i))
2002 sgilabel->boot_file[i] = aFile[i];
2003 else
2004 sgilabel->boot_file[i] = 0;
2005 i++;
2006 }
2007 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002008 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002009}
2010
2011static void
2012create_sgiinfo(void)
2013{
Rob Landleyb73451d2006-02-24 16:29:00 +00002014 /* I keep SGI's habit to write the sgilabel to the second block */
2015 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
2016 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
2017 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002018}
2019
Eric Andersen040f4402003-07-30 08:40:37 +00002020static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002021
2022static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002023sgi_write_table(void)
2024{
2025 sgilabel->csum = 0;
2026 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
2027 (unsigned int*)sgilabel, sizeof(*sgilabel)));
2028 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00002029 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00002030
2031 if (lseek(fd, 0, SEEK_SET) < 0)
2032 fdisk_fatal(unable_to_seek);
2033 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
2034 fdisk_fatal(unable_to_write);
2035 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2036 /*
2037 * keep this habit of first writing the "sgilabel".
2038 * I never tested whether it works without (AN 981002).
2039 */
2040 sgiinfo *info = fill_sgiinfo();
2041 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2042 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2043 fdisk_fatal(unable_to_seek);
2044 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2045 fdisk_fatal(unable_to_write);
2046 free(info);
2047 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002048}
2049
2050static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002051compare_start(int *x, int *y)
2052{
2053 /*
2054 * sort according to start sectors
2055 * and prefers largest partition:
2056 * entry zero is entire disk entry
2057 */
2058 unsigned int i = *x;
2059 unsigned int j = *y;
2060 unsigned int a = sgi_get_start_sector(i);
2061 unsigned int b = sgi_get_start_sector(j);
2062 unsigned int c = sgi_get_num_sectors(i);
2063 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002064
Rob Landleyb73451d2006-02-24 16:29:00 +00002065 if (a == b)
2066 return (d > c) ? 1 : (d == c) ? 0 : -1;
2067 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002068}
2069
2070
2071static int
Eric Andersen040f4402003-07-30 08:40:37 +00002072verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002073{
Rob Landleyb73451d2006-02-24 16:29:00 +00002074 int Index[16]; /* list of valid partitions */
2075 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2076 int entire = 0, i = 0;
2077 unsigned int start = 0;
2078 long long gap = 0; /* count unused blocks */
2079 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002080
Rob Landleyb73451d2006-02-24 16:29:00 +00002081 clearfreelist();
2082 for (i = 0; i < 16; i++) {
2083 if (sgi_get_num_sectors(i) != 0) {
2084 Index[sortcount++] = i;
2085 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2086 if (entire++ == 1) {
2087 if (verbose)
2088 printf(_("More than one entire disk entry present.\n"));
2089 }
2090 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002091 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002092 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002093 if (sortcount == 0) {
2094 if (verbose)
2095 printf(_("No partitions defined\n"));
2096 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2097 }
2098 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2099 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2100 if ((Index[0] != 10) && verbose)
2101 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2102 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2103 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002104 "at block 0,\n"
2105 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002106 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002107 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002108 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2109 printf(_("The entire disk partition is only %d diskblock large,\n"
2110 "but the disk is %d diskblocks long.\n"),
2111 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002112 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002113 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002114 if (verbose)
2115 printf(_("One Partition (#11) should cover the entire disk.\n"));
2116 if (debug > 2)
2117 printf("sysid=%d\tpartition=%d\n",
2118 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002119 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002120 for (i = 1, start = 0; i < sortcount; i++) {
2121 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2122
2123 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2124 if (debug) /* I do not understand how some disks fulfil it */
2125 if (verbose)
2126 printf(_("Partition %d does not start on cylinder boundary.\n"),
2127 Index[i]+1);
2128 }
2129 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2130 if (debug) /* I do not understand how some disks fulfil it */
2131 if (verbose)
2132 printf(_("Partition %d does not end on cylinder boundary.\n"),
2133 Index[i]+1);
2134 }
2135 /* We cannot handle several "entire disk" entries. */
2136 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2137 if (start > sgi_get_start_sector(Index[i])) {
2138 if (verbose)
2139 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2140 Index[i-1]+1, Index[i]+1,
2141 start - sgi_get_start_sector(Index[i]));
2142 if (gap > 0) gap = -gap;
2143 if (gap == 0) gap = -1;
2144 }
2145 if (start < sgi_get_start_sector(Index[i])) {
2146 if (verbose)
2147 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2148 sgi_get_start_sector(Index[i]) - start,
2149 start, sgi_get_start_sector(Index[i])-1);
2150 gap += sgi_get_start_sector(Index[i]) - start;
2151 add2freelist(start, sgi_get_start_sector(Index[i]));
2152 }
2153 start = sgi_get_start_sector(Index[i])
2154 + sgi_get_num_sectors(Index[i]);
2155 if (debug > 1) {
2156 if (verbose)
2157 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2158 sgi_get_start_sector(Index[i]),
2159 sgi_get_num_sectors(Index[i]),
2160 sgi_get_sysid(Index[i]));
2161 }
2162 }
2163 if (start < lastblock) {
2164 if (verbose)
2165 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2166 lastblock - start, start, lastblock-1);
2167 gap += lastblock - start;
2168 add2freelist(start, lastblock);
2169 }
2170 /*
2171 * Done with arithmetics
2172 * Go for details now
2173 */
2174 if (verbose) {
2175 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2176 printf(_("\nThe boot partition does not exist.\n"));
2177 }
2178 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2179 printf(_("\nThe swap partition does not exist.\n"));
2180 } else {
2181 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2182 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2183 printf(_("\nThe swap partition has no swap type.\n"));
2184 }
2185 if (sgi_check_bootfile("/unix"))
2186 printf(_("\tYou have chosen an unusual boot file name.\n"));
2187 }
2188 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002189}
2190
2191static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002192sgi_gaps(void)
2193{
2194 /*
2195 * returned value is:
2196 * = 0 : disk is properly filled to the rim
2197 * < 0 : there is an overlap
2198 * > 0 : there is still some vacant space
2199 */
2200 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002201}
2202
2203static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002204sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002205{
Rob Landleyb73451d2006-02-24 16:29:00 +00002206 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2207 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2208 return;
2209 }
2210 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2211 && (sgi_get_start_sector(i) < 1) ) {
2212 read_chars(
2213 _("It is highly recommended that the partition at offset 0\n"
2214 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2215 "retrieve from its directory standalone tools like sash and fx.\n"
2216 "Only the \"SGI volume\" entire disk section may violate this.\n"
2217 "Type YES if you are sure about tagging this partition differently.\n"));
2218 if (strcmp(line_ptr, _("YES\n")))
2219 return;
2220 }
2221 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002222}
2223
2224/* returns partition index of first entry marked as entire disk */
2225static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002226sgi_entire(void)
2227{
2228 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002229
Rob Landleyb73451d2006-02-24 16:29:00 +00002230 for (i = 0; i < 16; i++)
2231 if (sgi_get_sysid(i) == SGI_VOLUME)
2232 return i;
2233 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002234}
2235
2236static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002237sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2238{
2239 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2240 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2241 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2242 set_changed(i);
2243 if (sgi_gaps() < 0) /* rebuild freelist */
2244 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002245}
2246
2247static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002248sgi_set_entire(void)
2249{
2250 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002251
Rob Landleyb73451d2006-02-24 16:29:00 +00002252 for (n = 10; n < partitions; n++) {
2253 if(!sgi_get_num_sectors(n) ) {
2254 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2255 break;
2256 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002257 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002258}
2259
2260static void
2261sgi_set_volhdr(void)
2262{
Rob Landleyb73451d2006-02-24 16:29:00 +00002263 int n;
2264
2265 for (n = 8; n < partitions; n++) {
2266 if (!sgi_get_num_sectors(n)) {
2267 /*
2268 * 5 cylinders is an arbitrary value I like
2269 * IRIX 5.3 stored files in the volume header
2270 * (like sash, symmon, fx, ide) with ca. 3200
2271 * sectors.
2272 */
2273 if (heads * sectors * 5 < sgi_get_lastblock())
2274 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2275 break;
2276 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002277 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002278}
2279
2280static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002281sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002282{
Rob Landleyb73451d2006-02-24 16:29:00 +00002283 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002284}
2285
2286static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002287sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002288{
Rob Landleyb73451d2006-02-24 16:29:00 +00002289 char mesg[256];
2290 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002291
Rob Landleyb73451d2006-02-24 16:29:00 +00002292 if (n == 10) {
2293 sys = SGI_VOLUME;
2294 } else if (n == 8) {
2295 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002296 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002297 if(sgi_get_num_sectors(n)) {
2298 printf(_("Partition %d is already defined. Delete "
2299 "it before re-adding it.\n"), n + 1);
2300 return;
2301 }
2302 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2303 printf(_("Attempting to generate entire disk entry automatically.\n"));
2304 sgi_set_entire();
2305 sgi_set_volhdr();
2306 }
2307 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2308 printf(_("The entire disk is already covered with partitions.\n"));
2309 return;
2310 }
2311 if (sgi_gaps() < 0) {
2312 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2313 return;
2314 }
2315 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2316 while (1) {
2317 if(sys == SGI_VOLUME) {
2318 last = sgi_get_lastblock();
2319 first = read_int(0, 0, last-1, 0, mesg);
2320 if (first != 0) {
2321 printf(_("It is highly recommended that eleventh partition\n"
2322 "covers the entire disk and is of type `SGI volume'\n"));
2323 }
2324 } else {
2325 first = freelist[0].first;
2326 last = freelist[0].last;
2327 first = read_int(scround(first), scround(first), scround(last)-1,
2328 0, mesg);
2329 }
2330 if (display_in_cyl_units)
2331 first *= units_per_sector;
2332 else
2333 first = first; /* align to cylinder if you know how ... */
2334 if(!last )
2335 last = isinfreelist(first);
2336 if(last == 0) {
2337 printf(_("You will get a partition overlap on the disk. "
2338 "Fix it first!\n"));
2339 } else
2340 break;
2341 }
2342 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2343 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2344 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002345 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002346 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002347 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002348 last = last; /* align to cylinder if You know how ... */
2349 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2350 printf(_("It is highly recommended that eleventh partition\n"
2351 "covers the entire disk and is of type `SGI volume'\n"));
2352 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002353}
2354
Eric Andersen040f4402003-07-30 08:40:37 +00002355#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002356static void
2357create_sgilabel(void)
2358{
Rob Landleyb73451d2006-02-24 16:29:00 +00002359 struct hd_geometry geometry;
2360 struct {
2361 unsigned int start;
2362 unsigned int nsect;
2363 int sysid;
2364 } old[4];
2365 int i = 0;
2366 long longsectors; /* the number of sectors on the device */
2367 int res; /* the result from the ioctl */
2368 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002369
Rob Landleyb73451d2006-02-24 16:29:00 +00002370 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002371
Rob Landleyb73451d2006-02-24 16:29:00 +00002372 fprintf( stderr,
2373 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2374 "until you decide to write them. After that, of course, the previous\n"
2375 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002376
Rob Landleyb73451d2006-02-24 16:29:00 +00002377 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
2378 res = ioctl(fd, BLKGETSIZE, &longsectors);
2379 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2380 heads = geometry.heads;
2381 sectors = geometry.sectors;
2382 if (res == 0) {
2383 /* the get device size ioctl was successful */
2384 cylinders = longsectors / (heads * sectors);
2385 cylinders /= sec_fac;
2386 } else {
2387 /* otherwise print error and use truncated version */
2388 cylinders = geometry.cylinders;
2389 fprintf(stderr,
2390 _("Warning: BLKGETSIZE ioctl failed on %s. "
2391 "Using geometry cylinder value of %d.\n"
2392 "This value may be truncated for devices"
2393 " > 33.8 GB.\n"), disk_device, cylinders);
2394 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002395 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002396 for (i = 0; i < 4; i++) {
2397 old[i].sysid = 0;
2398 if (valid_part_table_flag(MBRbuffer)) {
2399 if(get_part_table(i)->sys_ind) {
2400 old[i].sysid = get_part_table(i)->sys_ind;
2401 old[i].start = get_start_sect(get_part_table(i));
2402 old[i].nsect = get_nr_sects(get_part_table(i));
2403 printf(_("Trying to keep parameters of partition %d.\n"), i);
2404 if (debug)
2405 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2406 old[i].sysid, old[i].start, old[i].nsect);
2407 }
2408 }
2409 }
Eric Andersen040f4402003-07-30 08:40:37 +00002410
Rob Landleyb73451d2006-02-24 16:29:00 +00002411 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2412 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2413 sgilabel->boot_part = SGI_SSWAP16(0);
2414 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002415
Rob Landleyb73451d2006-02-24 16:29:00 +00002416 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2417 memset(sgilabel->boot_file, 0, 16);
2418 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002419
Rob Landleyb73451d2006-02-24 16:29:00 +00002420 sgilabel->devparam.skew = (0);
2421 sgilabel->devparam.gap1 = (0);
2422 sgilabel->devparam.gap2 = (0);
2423 sgilabel->devparam.sparecyl = (0);
2424 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2425 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2426 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002427 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002428 sgilabel->devparam.cmd_tag_queue_depth = (0);
2429 sgilabel->devparam.unused0 = (0);
2430 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2431 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002432 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002433 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2434 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2435 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002436 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002437 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2438 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2439 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2440 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2441 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2442 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2443 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2444 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2445 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2446 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2447 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2448 sgi_label = 1;
2449 partitions = 16;
2450 sgi_volumes = 15;
2451 sgi_set_entire();
2452 sgi_set_volhdr();
2453 for (i = 0; i < 4; i++) {
2454 if(old[i].sysid) {
2455 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2456 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002457 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002458}
2459
2460static void
2461sgi_set_xcyl(void)
2462{
Rob Landleyb73451d2006-02-24 16:29:00 +00002463 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002464}
Eric Andersen040f4402003-07-30 08:40:37 +00002465#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002466
2467/* _____________________________________________________________
2468 */
2469
Eric Andersen040f4402003-07-30 08:40:37 +00002470static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002471fill_sgiinfo(void)
2472{
Rob Landleyb73451d2006-02-24 16:29:00 +00002473 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002474
Rob Landleyb73451d2006-02-24 16:29:00 +00002475 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2476 info->b1 = SGI_SSWAP32(-1);
2477 info->b2 = SGI_SSWAP16(-1);
2478 info->b3 = SGI_SSWAP16(1);
2479 /* You may want to replace this string !!!!!!! */
2480 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2481 strcpy( (char*)info->serial, "0000" );
2482 info->check1816 = SGI_SSWAP16(18*256 +16 );
2483 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2484 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002485}
2486#endif /* SGI_LABEL */
2487
2488
2489#ifdef CONFIG_FEATURE_SUN_LABEL
2490/*
2491 * fdisksunlabel.c
2492 *
2493 * I think this is mostly, or entirely, due to
2494 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2495 *
2496 * Merged with fdisk for other architectures, aeb, June 1998.
2497 *
2498 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2499 * Internationalization
2500 */
2501
2502
Rob Landleyb73451d2006-02-24 16:29:00 +00002503static int sun_other_endian;
2504static int scsi_disk;
2505static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002506
2507#ifndef IDE0_MAJOR
2508#define IDE0_MAJOR 3
2509#endif
2510#ifndef IDE1_MAJOR
2511#define IDE1_MAJOR 22
2512#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002513
Rob Landleyb73451d2006-02-24 16:29:00 +00002514static void
2515guess_device_type(void)
2516{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002517 struct stat bootstat;
2518
Rob Landleyb73451d2006-02-24 16:29:00 +00002519 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002520 scsi_disk = 0;
2521 floppy = 0;
2522 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002523 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2524 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002525 scsi_disk = 0;
2526 floppy = 0;
2527 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002528 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002529 scsi_disk = 0;
2530 floppy = 1;
2531 } else {
2532 scsi_disk = 1;
2533 floppy = 0;
2534 }
2535}
2536
2537static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002538 { "\x00" "Empty" }, /* 0 */
2539 { "\x01" "Boot" }, /* 1 */
2540 { "\x02" "SunOS root" }, /* 2 */
2541 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2542 { "\x04" "SunOS usr" }, /* 4 */
2543 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2544 { "\x06" "SunOS stand" }, /* 6 */
2545 { "\x07" "SunOS var" }, /* 7 */
2546 { "\x08" "SunOS home" }, /* 8 */
2547 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2548 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2549 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002550/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002551 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2552 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002553};
2554
2555
2556static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002557set_sun_partition(int i, uint start, uint stop, int sysid)
2558{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002559 sunlabel->infos[i].id = sysid;
2560 sunlabel->partitions[i].start_cylinder =
2561 SUN_SSWAP32(start / (heads * sectors));
2562 sunlabel->partitions[i].num_sectors =
2563 SUN_SSWAP32(stop - start);
2564 set_changed(i);
2565}
2566
2567static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002568sun_nolabel(void)
2569{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002570 sun_label = 0;
2571 sunlabel->magic = 0;
2572 partitions = 4;
2573}
2574
2575static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002576check_sun_label(void)
2577{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002578 unsigned short *ush;
2579 int csum;
2580
Rob Landleyb73451d2006-02-24 16:29:00 +00002581 if (sunlabel->magic != SUN_LABEL_MAGIC
2582 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002583 sun_label = 0;
2584 sun_other_endian = 0;
2585 return 0;
2586 }
2587 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2588 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2589 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2590 if (csum) {
2591 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2592 "Probably you'll have to set all the values,\n"
2593 "e.g. heads, sectors, cylinders and partitions\n"
2594 "or force a fresh label (s command in main menu)\n"));
2595 } else {
2596 heads = SUN_SSWAP16(sunlabel->ntrks);
2597 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2598 sectors = SUN_SSWAP16(sunlabel->nsect);
2599 }
2600 update_units();
2601 sun_label = 1;
2602 partitions = 8;
2603 return 1;
2604}
2605
2606static const struct sun_predefined_drives {
2607 const char *vendor;
2608 const char *model;
2609 unsigned short sparecyl;
2610 unsigned short ncyl;
2611 unsigned short nacyl;
2612 unsigned short pcylcount;
2613 unsigned short ntrks;
2614 unsigned short nsect;
2615 unsigned short rspeed;
2616} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002617 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2618 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2619 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2620 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2621 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2622 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2623 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2624 { "","SUN0104",1,974,2,1019,6,35,3662},
2625 { "","SUN0207",4,1254,2,1272,9,36,3600},
2626 { "","SUN0327",3,1545,2,1549,9,46,3600},
2627 { "","SUN0340",0,1538,2,1544,6,72,4200},
2628 { "","SUN0424",2,1151,2,2500,9,80,4400},
2629 { "","SUN0535",0,1866,2,2500,7,80,5400},
2630 { "","SUN0669",5,1614,2,1632,15,54,3600},
2631 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2632 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2633 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2634 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2635 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002636};
2637
2638static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002639sun_autoconfigure_scsi(void)
2640{
2641 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002642
2643#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002644 unsigned int id[2];
2645 char buffer[2048];
2646 char buffer2[2048];
2647 FILE *pfd;
2648 char *vendor;
2649 char *model;
2650 char *q;
2651 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002652
Rob Landleyb73451d2006-02-24 16:29:00 +00002653 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2654 sprintf(buffer,
2655 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002656#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002657 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002658#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002659 /* This is very wrong (works only if you have one HBA),
2660 but I haven't found a way how to get hostno
2661 from the current kernel */
2662 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002663#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002664 (id[0]>>16) & 0xff,
2665 id[0] & 0xff,
2666 (id[0]>>8) & 0xff
2667 );
2668 pfd = fopen("/proc/scsi/scsi","r");
2669 if (pfd) {
2670 while (fgets(buffer2, 2048, pfd)) {
2671 if (!strcmp(buffer, buffer2)) {
2672 if (fgets(buffer2,2048,pfd)) {
2673 q = strstr(buffer2,"Vendor: ");
2674 if (q) {
2675 q += 8;
2676 vendor = q;
2677 q = strstr(q," ");
2678 *q++ = 0; /* truncate vendor name */
2679 q = strstr(q,"Model: ");
2680 if (q) {
2681 *q = 0;
2682 q += 7;
2683 model = q;
2684 q = strstr(q," Rev: ");
2685 if (q) {
2686 *q = 0;
2687 for (i = 0; i < SIZE(sun_drives); i++) {
2688 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2689 continue;
2690 if (!strstr(model, sun_drives[i].model))
2691 continue;
2692 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2693 p = sun_drives + i;
2694 break;
2695 }
2696 }
2697 }
2698 }
2699 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002700 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002701 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002702 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002703 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002704 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002705 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002706#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002707 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002708}
2709
Rob Landleyb73451d2006-02-24 16:29:00 +00002710static void
2711create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002712{
2713 struct hd_geometry geometry;
2714 unsigned int ndiv;
2715 int i;
2716 unsigned char c;
2717 const struct sun_predefined_drives *p = NULL;
2718
2719 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002720 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2721 "until you decide to write them. After that, of course, the previous\n"
2722 "content won't be recoverable.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002723#if BYTE_ORDER == LITTLE_ENDIAN
2724 sun_other_endian = 1;
2725#else
2726 sun_other_endian = 0;
2727#endif
2728 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2729 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2730 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002731 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002732 " ? auto configure\n"
2733 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002734 for (i = 0; i < SIZE(sun_drives); i++) {
2735 printf(" %c %s%s%s\n",
2736 i + 'a', sun_drives[i].vendor,
2737 (*sun_drives[i].vendor) ? " " : "",
2738 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002739 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002740 while (1) {
2741 c = read_char(_("Select type (? for auto, 0 for custom): "));
2742 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2743 p = sun_drives + c - 'a';
2744 break;
2745 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2746 p = sun_drives + c - 'A';
2747 break;
2748 } else if (c == '0') {
2749 break;
2750 } else if (c == '?' && scsi_disk) {
2751 p = sun_autoconfigure_scsi();
2752 if (!p)
2753 printf(_("Autoconfigure failed.\n"));
2754 else
2755 break;
2756 }
2757 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002758 }
2759 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002760 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2761 heads = geometry.heads;
2762 sectors = geometry.sectors;
2763 cylinders = geometry.cylinders;
2764 } else {
2765 heads = 0;
2766 sectors = 0;
2767 cylinders = 0;
2768 }
2769 if (floppy) {
2770 sunlabel->nacyl = 0;
2771 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2772 sunlabel->rspeed = SUN_SSWAP16(300);
2773 sunlabel->ilfact = SUN_SSWAP16(1);
2774 sunlabel->sparecyl = 0;
2775 } else {
2776 heads = read_int(1,heads,1024,0,_("Heads"));
2777 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002778 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002779 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002780 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002781 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2782 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2783 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2784 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2785 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2786 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2787 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002788 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002789 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2790 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2791 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2792 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2793 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2794 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2795 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2796 sunlabel->ilfact = SUN_SSWAP16(1);
2797 cylinders = p->ncyl;
2798 heads = p->ntrks;
2799 sectors = p->nsect;
2800 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002801 }
2802
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002803 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002804 "%s%s%s cyl %d alt %d hd %d sec %d",
2805 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2806 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002807 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2808
2809 sunlabel->ntrks = SUN_SSWAP16(heads);
2810 sunlabel->nsect = SUN_SSWAP16(sectors);
2811 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2812 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002813 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002814 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002815 if (cylinders * heads * sectors >= 150 * 2048) {
2816 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2817 } else
2818 ndiv = cylinders * 2 / 3;
2819 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2820 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2821 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002822 }
2823 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2824 {
2825 unsigned short *ush = (unsigned short *)sunlabel;
2826 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002827 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002828 csum ^= *ush++;
2829 sunlabel->csum = csum;
2830 }
2831
2832 set_all_unchanged();
2833 set_changed(0);
2834 get_boot(create_empty_sun);
2835}
2836
2837static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002838toggle_sunflags(int i, unsigned char mask)
2839{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002840 if (sunlabel->infos[i].flags & mask)
2841 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002842 else
2843 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002844 set_changed(i);
2845}
2846
2847static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002848fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2849{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002850 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002851
2852 *start = 0;
2853 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002854 for (i = 0; i < partitions; i++) {
2855 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002856 && sunlabel->infos[i].id
2857 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002858 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2859 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2860 if (continuous) {
2861 if (starts[i] == *start)
2862 *start += lens[i];
2863 else if (starts[i] + lens[i] >= *stop)
2864 *stop = starts[i];
2865 else
2866 continuous = 0;
2867 /* There will be probably more gaps
2868 than one, so lets check afterwards */
2869 }
2870 } else {
2871 starts[i] = 0;
2872 lens[i] = 0;
2873 }
2874 }
2875}
2876
2877static uint *verify_sun_starts;
2878
2879static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002880verify_sun_cmp(int *a, int *b)
2881{
2882 if (*a == -1) return 1;
2883 if (*b == -1) return -1;
2884 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2885 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002886}
2887
2888static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002889verify_sun(void)
2890{
2891 uint starts[8], lens[8], start, stop;
2892 int i,j,k,starto,endo;
2893 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002894
Rob Landleyb73451d2006-02-24 16:29:00 +00002895 verify_sun_starts = starts;
2896 fetch_sun(starts,lens,&start,&stop);
2897 for (k = 0; k < 7; k++) {
2898 for (i = 0; i < 8; i++) {
2899 if (k && (lens[i] % (heads * sectors))) {
2900 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002901 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002902 if (lens[i]) {
2903 for (j = 0; j < i; j++)
2904 if (lens[j]) {
2905 if (starts[j] == starts[i]+lens[i]) {
2906 starts[j] = starts[i]; lens[j] += lens[i];
2907 lens[i] = 0;
2908 } else if (starts[i] == starts[j]+lens[j]){
2909 lens[j] += lens[i];
2910 lens[i] = 0;
2911 } else if (!k) {
2912 if (starts[i] < starts[j]+lens[j]
2913 && starts[j] < starts[i]+lens[i]) {
2914 starto = starts[i];
2915 if (starts[j] > starto)
2916 starto = starts[j];
2917 endo = starts[i]+lens[i];
2918 if (starts[j]+lens[j] < endo)
2919 endo = starts[j]+lens[j];
2920 printf(_("Partition %d overlaps with others in "
2921 "sectors %d-%d\n"), i+1, starto, endo);
2922 }
2923 }
2924 }
2925 }
2926 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002927 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002928 for (i = 0; i < 8; i++) {
2929 if (lens[i])
2930 array[i] = i;
2931 else
2932 array[i] = -1;
2933 }
2934 qsort(array,SIZE(array),sizeof(array[0]),
2935 (int (*)(const void *,const void *)) verify_sun_cmp);
2936 if (array[0] == -1) {
2937 printf(_("No partitions defined\n"));
2938 return;
2939 }
2940 stop = cylinders * heads * sectors;
2941 if (starts[array[0]])
2942 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2943 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2944 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2945 }
2946 start = starts[array[i]] + lens[array[i]];
2947 if (start < stop)
2948 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002949}
2950
2951static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002952add_sun_partition(int n, int sys)
2953{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002954 uint start, stop, stop2;
2955 uint starts[8], lens[8];
2956 int whole_disk = 0;
2957
2958 char mesg[256];
2959 int i, first, last;
2960
2961 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2962 printf(_("Partition %d is already defined. Delete "
2963 "it before re-adding it.\n"), n + 1);
2964 return;
2965 }
2966
2967 fetch_sun(starts,lens,&start,&stop);
2968 if (stop <= start) {
2969 if (n == 2)
2970 whole_disk = 1;
2971 else {
2972 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002973 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002974 return;
2975 }
2976 }
2977 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002978 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002979 if (whole_disk)
2980 first = read_int(0, 0, 0, 0, mesg);
2981 else
2982 first = read_int(scround(start), scround(stop)+1,
2983 scround(stop), 0, mesg);
2984 if (display_in_cyl_units)
2985 first *= units_per_sector;
2986 else
2987 /* Starting sector has to be properly aligned */
2988 first = (first + heads * sectors - 1) / (heads * sectors);
2989 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002990 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002991It is highly recommended that the third partition covers the whole disk\n\
2992and is of type `Whole disk'\n");
2993 /* ewt asks to add: "don't start a partition at cyl 0"
2994 However, edmundo@rano.demon.co.uk writes:
2995 "In addition to having a Sun partition table, to be able to
2996 boot from the disc, the first partition, /dev/sdX1, must
2997 start at cylinder 0. This means that /dev/sdX1 contains
2998 the partition table and the boot block, as these are the
2999 first two sectors of the disc. Therefore you must be
3000 careful what you use /dev/sdX1 for. In particular, you must
3001 not use a partition starting at cylinder 0 for Linux swap,
3002 as that would overwrite the partition table and the boot
3003 block. You may, however, use such a partition for a UFS
3004 or EXT2 file system, as these file systems leave the first
3005 1024 bytes undisturbed. */
3006 /* On the other hand, one should not use partitions
3007 starting at block 0 in an md, or the label will
3008 be trashed. */
3009 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00003010 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003011 break;
3012 if (i < partitions && !whole_disk) {
3013 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003014 whole_disk = 1;
3015 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003016 }
3017 printf(_("Sector %d is already allocated\n"), first);
3018 } else
3019 break;
3020 }
3021 stop = cylinders * heads * sectors;
3022 stop2 = stop;
3023 for (i = 0; i < partitions; i++) {
3024 if (starts[i] > first && starts[i] < stop)
3025 stop = starts[i];
3026 }
3027 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00003028 _("Last %s or +size or +sizeM or +sizeK"),
3029 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003030 if (whole_disk)
3031 last = read_int(scround(stop2), scround(stop2), scround(stop2),
3032 0, mesg);
3033 else if (n == 2 && !first)
3034 last = read_int(scround(first), scround(stop2), scround(stop2),
3035 scround(first), mesg);
3036 else
3037 last = read_int(scround(first), scround(stop), scround(stop),
3038 scround(first), mesg);
3039 if (display_in_cyl_units)
3040 last *= units_per_sector;
3041 if (n == 2 && !first) {
3042 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003043 whole_disk = 1;
3044 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003045 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003046 printf(_("You haven't covered the whole disk with "
3047 "the 3rd partition, but your value\n"
3048 "%d %s covers some other partition. "
3049 "Your entry has been changed\n"
3050 "to %d %s\n"),
3051 scround(last), str_units(SINGULAR),
3052 scround(stop), str_units(SINGULAR));
3053 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003054 }
3055 } else if (!whole_disk && last > stop)
3056 last = stop;
3057
Rob Landleyb73451d2006-02-24 16:29:00 +00003058 if (whole_disk)
3059 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003060 set_sun_partition(n, first, last, sys);
3061}
3062
3063static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003064sun_delete_partition(int i)
3065{
Eric Andersen040f4402003-07-30 08:40:37 +00003066 unsigned int nsec;
3067
Rob Landleyb73451d2006-02-24 16:29:00 +00003068 if (i == 2
3069 && sunlabel->infos[i].id == WHOLE_DISK
3070 && !sunlabel->partitions[i].start_cylinder
3071 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003072 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003073 "consider leaving this\n"
3074 "partition as Whole disk (5), starting at 0, with %u "
3075 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003076 sunlabel->infos[i].id = 0;
3077 sunlabel->partitions[i].num_sectors = 0;
3078}
3079
3080static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003081sun_change_sysid(int i, int sys)
3082{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003083 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003084 read_chars(
3085 _("It is highly recommended that the partition at offset 0\n"
3086 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3087 "there may destroy your partition table and bootblock.\n"
3088 "Type YES if you're very sure you would like that partition\n"
3089 "tagged with 82 (Linux swap): "));
3090 if (strcmp (line_ptr, _("YES\n")))
3091 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003092 }
3093 switch (sys) {
3094 case SUNOS_SWAP:
3095 case LINUX_SWAP:
3096 /* swaps are not mountable by default */
3097 sunlabel->infos[i].flags |= 0x01;
3098 break;
3099 default:
3100 /* assume other types are mountable;
3101 user can change it anyway */
3102 sunlabel->infos[i].flags &= ~0x01;
3103 break;
3104 }
3105 sunlabel->infos[i].id = sys;
3106}
3107
3108static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003109sun_list_table(int xtra)
3110{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003111 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003112
3113 w = strlen(disk_device);
3114 if (xtra)
3115 printf(
3116 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3117 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3118 "%d extra sects/cyl, interleave %d:1\n"
3119 "%s\n"
3120 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003121 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3122 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3123 SUN_SSWAP16(sunlabel->pcylcount),
3124 SUN_SSWAP16(sunlabel->sparecyl),
3125 SUN_SSWAP16(sunlabel->ilfact),
3126 (char *)sunlabel,
3127 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003128 else
3129 printf(
3130 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3131 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003132 disk_device, heads, sectors, cylinders,
3133 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003134
3135 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003136 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003137 for (i = 0 ; i < partitions; i++) {
3138 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003139 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3140 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003141 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3142 partname(disk_device, i+1, w), /* device */
3143 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3144 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3145 (long) scround(start), /* start */
3146 (long) scround(start+len), /* end */
3147 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3148 sunlabel->infos[i].id, /* type id */
3149 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003150 }
3151 }
3152}
3153
Eric Andersen040f4402003-07-30 08:40:37 +00003154#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3155
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003156static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003157sun_set_alt_cyl(void)
3158{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003159 sunlabel->nacyl =
3160 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003161 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003162}
3163
3164static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003165sun_set_ncyl(int cyl)
3166{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003167 sunlabel->ncyl = SUN_SSWAP16(cyl);
3168}
3169
3170static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003171sun_set_xcyl(void)
3172{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003173 sunlabel->sparecyl =
3174 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003175 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003176}
3177
3178static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003179sun_set_ilfact(void)
3180{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003181 sunlabel->ilfact =
3182 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003183 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003184}
3185
3186static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003187sun_set_rspeed(void)
3188{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003189 sunlabel->rspeed =
3190 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003191 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003192}
3193
3194static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003195sun_set_pcylcount(void)
3196{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003197 sunlabel->pcylcount =
3198 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003199 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003200}
Eric Andersen040f4402003-07-30 08:40:37 +00003201#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003202
3203static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003204sun_write_table(void)
3205{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003206 unsigned short *ush = (unsigned short *)sunlabel;
3207 unsigned short csum = 0;
3208
Rob Landleyb73451d2006-02-24 16:29:00 +00003209 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003210 csum ^= *ush++;
3211 sunlabel->csum = csum;
3212 if (lseek(fd, 0, SEEK_SET) < 0)
3213 fdisk_fatal(unable_to_seek);
3214 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3215 fdisk_fatal(unable_to_write);
3216}
3217#endif /* SUN_LABEL */
3218
3219/* DOS partition types */
3220
3221static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003222 { "\x00" "Empty" },
3223 { "\x01" "FAT12" },
3224 { "\x04" "FAT16 <32M" },
3225 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3226 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3227 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3228 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3229 { "\x0b" "Win95 FAT32" },
3230 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3231 { "\x0e" "Win95 FAT16 (LBA)" },
3232 { "\x0f" "Win95 Ext'd (LBA)" },
3233 { "\x11" "Hidden FAT12" },
3234 { "\x12" "Compaq diagnostics" },
3235 { "\x14" "Hidden FAT16 <32M" },
3236 { "\x16" "Hidden FAT16" },
3237 { "\x17" "Hidden HPFS/NTFS" },
3238 { "\x1b" "Hidden Win95 FAT32" },
3239 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3240 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3241 { "\x3c" "PartitionMagic recovery" },
3242 { "\x41" "PPC PReP Boot" },
3243 { "\x42" "SFS" },
3244 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3245 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3246 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3247 { "\x82" "Linux swap" }, /* also Solaris */
3248 { "\x83" "Linux" },
3249 { "\x84" "OS/2 hidden C: drive" },
3250 { "\x85" "Linux extended" },
3251 { "\x86" "NTFS volume set" },
3252 { "\x87" "NTFS volume set" },
3253 { "\x8e" "Linux LVM" },
3254 { "\x9f" "BSD/OS" }, /* BSDI */
3255 { "\xa0" "IBM Thinkpad hibernation" },
3256 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3257 { "\xa6" "OpenBSD" },
3258 { "\xa8" "Darwin UFS" },
3259 { "\xa9" "NetBSD" },
3260 { "\xab" "Darwin boot" },
3261 { "\xb7" "BSDI fs" },
3262 { "\xb8" "BSDI swap" },
3263 { "\xbe" "Solaris boot" },
3264 { "\xeb" "BeOS fs" },
3265 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3266 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3267 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3268 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3269 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3270 autodetect using persistent
3271 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003272#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003273 { "\x02" "XENIX root" },
3274 { "\x03" "XENIX usr" },
3275 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3276 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3277 { "\x10" "OPUS" },
3278 { "\x18" "AST SmartSleep" },
3279 { "\x24" "NEC DOS" },
3280 { "\x39" "Plan 9" },
3281 { "\x40" "Venix 80286" },
3282 { "\x4d" "QNX4.x" },
3283 { "\x4e" "QNX4.x 2nd part" },
3284 { "\x4f" "QNX4.x 3rd part" },
3285 { "\x50" "OnTrack DM" },
3286 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3287 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3288 { "\x53" "OnTrack DM6 Aux3" },
3289 { "\x54" "OnTrackDM6" },
3290 { "\x55" "EZ-Drive" },
3291 { "\x56" "Golden Bow" },
3292 { "\x5c" "Priam Edisk" },
3293 { "\x61" "SpeedStor" },
3294 { "\x64" "Novell Netware 286" },
3295 { "\x65" "Novell Netware 386" },
3296 { "\x70" "DiskSecure Multi-Boot" },
3297 { "\x75" "PC/IX" },
3298 { "\x93" "Amoeba" },
3299 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3300 { "\xa7" "NeXTSTEP" },
3301 { "\xbb" "Boot Wizard hidden" },
3302 { "\xc1" "DRDOS/sec (FAT-12)" },
3303 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3304 { "\xc6" "DRDOS/sec (FAT-16)" },
3305 { "\xc7" "Syrinx" },
3306 { "\xda" "Non-FS data" },
3307 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003308 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003309 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3310 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3311 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003312 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003313 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3314 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003315 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003316 { "\xf1" "SpeedStor" },
3317 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3318 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3319 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003320#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003321 { 0 }
3322};
3323
3324
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003325
3326/* A valid partition table sector ends in 0x55 0xaa */
3327static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003328part_table_flag(const char *b)
3329{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003330 return ((uint) b[510]) + (((uint) b[511]) << 8);
3331}
3332
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003333
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 +00003336write_part_table_flag(char *b)
3337{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003338 b[510] = 0x55;
3339 b[511] = 0xaa;
3340}
3341
3342/* start_sect and nr_sects are stored little endian on all machines */
3343/* moreover, they are not aligned correctly */
3344static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003345store4_little_endian(unsigned char *cp, unsigned int val)
3346{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003347 cp[0] = (val & 0xff);
3348 cp[1] = ((val >> 8) & 0xff);
3349 cp[2] = ((val >> 16) & 0xff);
3350 cp[3] = ((val >> 24) & 0xff);
3351}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003352#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003353
3354static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003355read4_little_endian(const unsigned char *cp)
3356{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003357 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3358 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3359}
3360
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003361#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003362static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003363set_start_sect(struct partition *p, unsigned int start_sect)
3364{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003365 store4_little_endian(p->start4, start_sect);
3366}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003367#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003368
Eric Andersend9261492004-06-28 23:50:31 +00003369static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003370get_start_sect(const struct partition *p)
3371{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003372 return read4_little_endian(p->start4);
3373}
3374
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003375#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003376static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003377set_nr_sects(struct partition *p, int32_t nr_sects)
3378{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003379 store4_little_endian(p->size4, nr_sects);
3380}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003381#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003382
Eric Andersend9261492004-06-28 23:50:31 +00003383static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003384get_nr_sects(const struct partition *p)
3385{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003386 return read4_little_endian(p->size4);
3387}
3388
3389/* normally O_RDWR, -l option gives O_RDONLY */
3390static int type_open = O_RDWR;
3391
3392
Rob Landleyb73451d2006-02-24 16:29:00 +00003393static int ext_index; /* the prime extended partition */
3394static int listing; /* no aborts for fdisk -l */
3395static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003396#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3397static int dos_changed;
3398static int nowarn; /* no warnings for fdisk -l/-s */
3399#endif
3400
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003401
3402
Rob Landleyb73451d2006-02-24 16:29:00 +00003403static uint user_cylinders, user_heads, user_sectors;
3404static uint pt_heads, pt_sectors;
3405static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003406
Eric Andersend9261492004-06-28 23:50:31 +00003407static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003408
Eric Andersen040f4402003-07-30 08:40:37 +00003409static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003410
3411
3412static jmp_buf listingbuf;
3413
Rob Landleyb73451d2006-02-24 16:29:00 +00003414static void fdisk_fatal(enum failure why)
3415{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003416 const char *message;
3417
3418 if (listing) {
3419 close(fd);
3420 longjmp(listingbuf, 1);
3421 }
3422
3423 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003424 case unable_to_open:
3425 message = "Unable to open %s\n";
3426 break;
3427 case unable_to_read:
3428 message = "Unable to read %s\n";
3429 break;
3430 case unable_to_seek:
3431 message = "Unable to seek on %s\n";
3432 break;
3433 case unable_to_write:
3434 message = "Unable to write %s\n";
3435 break;
3436 case ioctl_error:
3437 message = "BLKGETSIZE ioctl failed on %s\n";
3438 break;
3439 default:
3440 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003441 }
3442
3443 fputc('\n', stderr);
3444 fprintf(stderr, message, disk_device);
3445 exit(1);
3446}
3447
3448static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003449seek_sector(off_t secno)
3450{
Eric Andersen0a92f352004-03-30 09:21:54 +00003451 off_t offset = secno * sector_size;
3452 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003453 fdisk_fatal(unable_to_seek);
3454}
3455
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003456#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003457static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003458write_sector(off_t secno, char *buf)
3459{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003460 seek_sector(secno);
3461 if (write(fd, buf, sector_size) != sector_size)
3462 fdisk_fatal(unable_to_write);
3463}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003464#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003465
3466/* Allocate a buffer and read a partition table sector */
3467static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003468read_pte(struct pte *pe, off_t offset)
3469{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003470 pe->offset = offset;
3471 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003472 seek_sector(offset);
3473 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3474 fdisk_fatal(unable_to_read);
3475#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003476 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003477#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003478 pe->part_table = pe->ext_pointer = NULL;
3479}
3480
3481static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003482get_partition_start(const struct pte *pe)
3483{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003484 return pe->offset + get_start_sect(pe->part_table);
3485}
3486
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003487#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003488/*
3489 * Avoid warning about DOS partitions when no DOS partition was changed.
3490 * Here a heuristic "is probably dos partition".
3491 * We might also do the opposite and warn in all cases except
3492 * for "is probably nondos partition".
3493 */
3494static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003495is_dos_partition(int t)
3496{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003497 return (t == 1 || t == 4 || t == 6 ||
3498 t == 0x0b || t == 0x0c || t == 0x0e ||
3499 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3500 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3501 t == 0xc1 || t == 0xc4 || t == 0xc6);
3502}
3503
3504static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003505menu(void)
3506{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003507#ifdef CONFIG_FEATURE_SUN_LABEL
3508 if (sun_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003509 puts(_("Command action"));
3510 puts(_("\ta\ttoggle a read only flag")); /* sun */
3511 puts(_("\tb\tedit bsd disklabel"));
3512 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3513 puts(_("\td\tdelete a partition"));
3514 puts(_("\tl\tlist known partition types"));
3515 puts(_("\tm\tprint this menu"));
3516 puts(_("\tn\tadd a new partition"));
3517 puts(_("\to\tcreate a new empty DOS partition table"));
3518 puts(_("\tp\tprint the partition table"));
3519 puts(_("\tq\tquit without saving changes"));
3520 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3521 puts(_("\tt\tchange a partition's system id"));
3522 puts(_("\tu\tchange display/entry units"));
3523 puts(_("\tv\tverify the partition table"));
3524 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003525#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003526 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003527#endif
3528 } else
3529#endif
3530#ifdef CONFIG_FEATURE_SGI_LABEL
3531 if (sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003532 puts(_("Command action"));
3533 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3534 puts(_("\tb\tedit bootfile entry")); /* sgi */
3535 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3536 puts(_("\td\tdelete a partition"));
3537 puts(_("\tl\tlist known partition types"));
3538 puts(_("\tm\tprint this menu"));
3539 puts(_("\tn\tadd a new partition"));
3540 puts(_("\to\tcreate a new empty DOS partition table"));
3541 puts(_("\tp\tprint the partition table"));
3542 puts(_("\tq\tquit without saving changes"));
3543 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3544 puts(_("\tt\tchange a partition's system id"));
3545 puts(_("\tu\tchange display/entry units"));
3546 puts(_("\tv\tverify the partition table"));
3547 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003548 } else
3549#endif
3550#ifdef CONFIG_FEATURE_AIX_LABEL
3551 if (aix_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003552 puts(_("Command action"));
3553 puts(_("\tm\tprint this menu"));
3554 puts(_("\to\tcreate a new empty DOS partition table"));
3555 puts(_("\tq\tquit without saving changes"));
3556 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003557 } else
3558#endif
3559 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003560 puts(_("Command action"));
3561 puts(_("\ta\ttoggle a bootable flag"));
3562 puts(_("\tb\tedit bsd disklabel"));
3563 puts(_("\tc\ttoggle the dos compatibility flag"));
3564 puts(_("\td\tdelete a partition"));
3565 puts(_("\tl\tlist known partition types"));
3566 puts(_("\tm\tprint this menu"));
3567 puts(_("\tn\tadd a new partition"));
3568 puts(_("\to\tcreate a new empty DOS partition table"));
3569 puts(_("\tp\tprint the partition table"));
3570 puts(_("\tq\tquit without saving changes"));
3571 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3572 puts(_("\tt\tchange a partition's system id"));
3573 puts(_("\tu\tchange display/entry units"));
3574 puts(_("\tv\tverify the partition table"));
3575 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003576#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003577 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003578#endif
3579 }
3580}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003581#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3582
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003583
3584#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3585static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003586xmenu(void)
3587{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003588#ifdef CONFIG_FEATURE_SUN_LABEL
3589 if (sun_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003590 puts(_("Command action"));
3591 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3592 puts(_("\tc\tchange number of cylinders"));
3593 puts(_("\td\tprint the raw data in the partition table"));
3594 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3595 puts(_("\th\tchange number of heads"));
3596 puts(_("\ti\tchange interleave factor")); /*sun*/
3597 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3598 puts(_("\tm\tprint this menu"));
3599 puts(_("\tp\tprint the partition table"));
3600 puts(_("\tq\tquit without saving changes"));
3601 puts(_("\tr\treturn to main menu"));
3602 puts(_("\ts\tchange number of sectors/track"));
3603 puts(_("\tv\tverify the partition table"));
3604 puts(_("\tw\twrite table to disk and exit"));
3605 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003606 } else
3607#endif
3608#ifdef CONFIG_FEATURE_SGI_LABEL
3609 if (sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003610 puts(_("Command action"));
3611 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3612 puts(_("\tc\tchange number of cylinders"));
3613 puts(_("\td\tprint the raw data in the partition table"));
3614 puts(_("\te\tlist extended partitions")); /* !sun */
3615 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3616 puts(_("\th\tchange number of heads"));
3617 puts(_("\tm\tprint this menu"));
3618 puts(_("\tp\tprint the partition table"));
3619 puts(_("\tq\tquit without saving changes"));
3620 puts(_("\tr\treturn to main menu"));
3621 puts(_("\ts\tchange number of sectors/track"));
3622 puts(_("\tv\tverify the partition table"));
3623 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003624 } else
3625#endif
3626#ifdef CONFIG_FEATURE_AIX_LABEL
3627 if (aix_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003628 puts(_("Command action"));
3629 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3630 puts(_("\tc\tchange number of cylinders"));
3631 puts(_("\td\tprint the raw data in the partition table"));
3632 puts(_("\te\tlist extended partitions")); /* !sun */
3633 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3634 puts(_("\th\tchange number of heads"));
3635 puts(_("\tm\tprint this menu"));
3636 puts(_("\tp\tprint the partition table"));
3637 puts(_("\tq\tquit without saving changes"));
3638 puts(_("\tr\treturn to main menu"));
3639 puts(_("\ts\tchange number of sectors/track"));
3640 puts(_("\tv\tverify the partition table"));
3641 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003642 } else
3643#endif
3644 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003645 puts(_("Command action"));
3646 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3647 puts(_("\tc\tchange number of cylinders"));
3648 puts(_("\td\tprint the raw data in the partition table"));
3649 puts(_("\te\tlist extended partitions")); /* !sun */
3650 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003651#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003652 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003653#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003654 puts(_("\th\tchange number of heads"));
3655 puts(_("\tm\tprint this menu"));
3656 puts(_("\tp\tprint the partition table"));
3657 puts(_("\tq\tquit without saving changes"));
3658 puts(_("\tr\treturn to main menu"));
3659 puts(_("\ts\tchange number of sectors/track"));
3660 puts(_("\tv\tverify the partition table"));
3661 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003662 }
3663}
3664#endif /* ADVANCED mode */
3665
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003666#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003667static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003668get_sys_types(void)
3669{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003670 return (
3671#ifdef CONFIG_FEATURE_SUN_LABEL
3672 sun_label ? sun_sys_types :
3673#endif
3674#ifdef CONFIG_FEATURE_SGI_LABEL
3675 sgi_label ? sgi_sys_types :
3676#endif
3677 i386_sys_types);
3678}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003679#else
3680#define get_sys_types() i386_sys_types
3681#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003682
3683static const char *partition_type(unsigned char type)
3684{
3685 int i;
3686 const struct systypes *types = get_sys_types();
3687
Rob Landleyb73451d2006-02-24 16:29:00 +00003688 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003689 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003690 return types[i].name + 1;
3691
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003692 return _("Unknown");
3693}
3694
3695
3696#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3697static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003698get_sysid(int i)
3699{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003700 return (
3701#ifdef CONFIG_FEATURE_SUN_LABEL
3702 sun_label ? sunlabel->infos[i].id :
3703#endif
3704#ifdef CONFIG_FEATURE_SGI_LABEL
3705 sgi_label ? sgi_get_sysid(i) :
3706#endif
3707 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003708}
3709
3710void list_types(const struct systypes *sys)
3711{
3712 uint last[4], done = 0, next = 0, size;
3713 int i;
3714
3715 for (i = 0; sys[i].name; i++);
3716 size = i;
3717
3718 for (i = 3; i >= 0; i--)
3719 last[3 - i] = done += (size + i - done) / (i + 1);
3720 i = done = 0;
3721
3722 do {
3723 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003724 (unsigned char)sys[next].name[0],
3725 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003726 next = last[i++] + done;
3727 if (i > 3 || next >= last[i]) {
3728 i = 0;
3729 next = ++done;
3730 }
3731 } while (done < last[0]);
3732 putchar('\n');
3733}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003734#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003735
3736static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003737is_cleared_partition(const struct partition *p)
3738{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003739 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3740 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3741 get_start_sect(p) || get_nr_sects(p));
3742}
3743
3744static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003745clear_partition(struct partition *p)
3746{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003747 if (!p)
3748 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003749 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003750}
3751
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003752#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003753static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003754set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3755{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003756 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003757 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003758
3759 if (doext) {
3760 p = ptes[i].ext_pointer;
3761 offset = extended_offset;
3762 } else {
3763 p = ptes[i].part_table;
3764 offset = ptes[i].offset;
3765 }
3766 p->boot_ind = 0;
3767 p->sys_ind = sysid;
3768 set_start_sect(p, start - offset);
3769 set_nr_sects(p, stop - start + 1);
3770 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3771 start = heads*sectors*1024 - 1;
3772 set_hsc(p->head, p->sector, p->cyl, start);
3773 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3774 stop = heads*sectors*1024 - 1;
3775 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3776 ptes[i].changed = 1;
3777}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003778#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003779
3780static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003781test_c(const char **m, const char *mesg)
3782{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003783 int val = 0;
3784 if (!*m)
3785 fprintf(stderr, _("You must set"));
3786 else {
3787 fprintf(stderr, " %s", *m);
3788 val = 1;
3789 }
3790 *m = mesg;
3791 return val;
3792}
3793
3794static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003795warn_geometry(void)
3796{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003797 const char *m = NULL;
3798 int prev = 0;
3799
3800 if (!heads)
3801 prev = test_c(&m, _("heads"));
3802 if (!sectors)
3803 prev = test_c(&m, _("sectors"));
3804 if (!cylinders)
3805 prev = test_c(&m, _("cylinders"));
3806 if (!m)
3807 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003808
3809 fprintf(stderr, "%s%s.\n"
3810#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3811 "You can do this from the extra functions menu.\n"
3812#endif
3813 , prev ? _(" and ") : " ", m);
3814
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003815 return 1;
3816}
3817
3818static void update_units(void)
3819{
3820 int cyl_units = heads * sectors;
3821
3822 if (display_in_cyl_units && cyl_units)
3823 units_per_sector = cyl_units;
3824 else
3825 units_per_sector = 1; /* in sectors */
3826}
3827
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003828#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003829static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003830warn_cylinders(void)
3831{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003832 if (dos_label && cylinders > 1024 && !nowarn)
3833 fprintf(stderr, _("\n"
3834"The number of cylinders for this disk is set to %d.\n"
3835"There is nothing wrong with that, but this is larger than 1024,\n"
3836"and could in certain setups cause problems with:\n"
3837"1) software that runs at boot time (e.g., old versions of LILO)\n"
3838"2) booting and partitioning software from other OSs\n"
3839" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3840 cylinders);
3841}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003842#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003843
3844static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003845read_extended(int ext)
3846{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003847 int i;
3848 struct pte *pex;
3849 struct partition *p, *q;
3850
3851 ext_index = ext;
3852 pex = &ptes[ext];
3853 pex->ext_pointer = pex->part_table;
3854
3855 p = pex->part_table;
3856 if (!get_start_sect(p)) {
3857 fprintf(stderr,
3858 _("Bad offset in primary extended partition\n"));
3859 return;
3860 }
3861
Rob Landleyb73451d2006-02-24 16:29:00 +00003862 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003863 struct pte *pe = &ptes[partitions];
3864
3865 if (partitions >= MAXIMUM_PARTS) {
3866 /* This is not a Linux restriction, but
3867 this program uses arrays of size MAXIMUM_PARTS.
3868 Do not try to `improve' this test. */
3869 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003870#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003871 fprintf(stderr,
3872 _("Warning: deleting partitions after %d\n"),
3873 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003874 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003875#endif
3876 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003877 return;
3878 }
3879
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003880 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003881
3882 if (!extended_offset)
3883 extended_offset = get_start_sect(p);
3884
3885 q = p = pt_offset(pe->sectorbuffer, 0);
3886 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003887 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003888 if (pe->ext_pointer)
3889 fprintf(stderr,
3890 _("Warning: extra link "
3891 "pointer in partition table"
3892 " %d\n"), partitions + 1);
3893 else
3894 pe->ext_pointer = p;
3895 } else if (p->sys_ind) {
3896 if (pe->part_table)
3897 fprintf(stderr,
3898 _("Warning: ignoring extra "
3899 "data in partition table"
3900 " %d\n"), partitions + 1);
3901 else
3902 pe->part_table = p;
3903 }
3904 }
3905
3906 /* very strange code here... */
3907 if (!pe->part_table) {
3908 if (q != pe->ext_pointer)
3909 pe->part_table = q;
3910 else
3911 pe->part_table = q + 1;
3912 }
3913 if (!pe->ext_pointer) {
3914 if (q != pe->part_table)
3915 pe->ext_pointer = q;
3916 else
3917 pe->ext_pointer = q + 1;
3918 }
3919
3920 p = pe->ext_pointer;
3921 partitions++;
3922 }
3923
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003924#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003925 /* remove empty links */
3926 remove:
3927 for (i = 4; i < partitions; i++) {
3928 struct pte *pe = &ptes[i];
3929
3930 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003931 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003932 printf("omitting empty partition (%d)\n", i+1);
3933 delete_partition(i);
3934 goto remove; /* numbering changed */
3935 }
3936 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003937#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003938}
3939
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003940#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003941static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003942create_doslabel(void)
3943{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003944 int i;
3945
3946 fprintf(stderr,
3947 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3948 "until you decide to write them. After that, of course, the previous\n"
3949 "content won't be recoverable.\n\n"));
3950#ifdef CONFIG_FEATURE_SUN_LABEL
3951 sun_nolabel(); /* otherwise always recognised as sun */
3952#endif
3953#ifdef CONFIG_FEATURE_SGI_LABEL
3954 sgi_nolabel(); /* otherwise always recognised as sgi */
3955#endif
3956#ifdef CONFIG_FEATURE_AIX_LABEL
3957 aix_label = 0;
3958#endif
3959#ifdef CONFIG_FEATURE_OSF_LABEL
3960 osf_label = 0;
3961 possibly_osf_label = 0;
3962#endif
3963 partitions = 4;
3964
3965 for (i = 510-64; i < 510; i++)
3966 MBRbuffer[i] = 0;
3967 write_part_table_flag(MBRbuffer);
3968 extended_offset = 0;
3969 set_all_unchanged();
3970 set_changed(0);
3971 get_boot(create_empty_dos);
3972}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003973#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003974
3975static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003976get_sectorsize(void)
3977{
Rob Landley736e5252006-02-25 03:36:00 +00003978 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003979 int arg;
3980 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3981 sector_size = arg;
3982 if (sector_size != DEFAULT_SECTOR_SIZE)
3983 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003984 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003985 }
3986}
3987
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003988static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003989get_kernel_geometry(void)
3990{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003991 struct hd_geometry geometry;
3992
3993 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3994 kern_heads = geometry.heads;
3995 kern_sectors = geometry.sectors;
3996 /* never use geometry.cylinders - it is truncated */
3997 }
3998}
3999
4000static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004001get_partition_table_geometry(void)
4002{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00004003 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004004 struct partition *p;
4005 int i, h, s, hh, ss;
4006 int first = 1;
4007 int bad = 0;
4008
Eric Andersen3496fdc2006-01-30 23:09:20 +00004009 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004010 return;
4011
4012 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00004013 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004014 p = pt_offset(bufp, i);
4015 if (p->sys_ind != 0) {
4016 h = p->end_head + 1;
4017 s = (p->end_sector & 077);
4018 if (first) {
4019 hh = h;
4020 ss = s;
4021 first = 0;
4022 } else if (hh != h || ss != s)
4023 bad = 1;
4024 }
4025 }
4026
4027 if (!first && !bad) {
4028 pt_heads = hh;
4029 pt_sectors = ss;
4030 }
4031}
4032
Rob Landleyb73451d2006-02-24 16:29:00 +00004033static void
4034get_geometry(void)
4035{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004036 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00004037 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004038
4039 get_sectorsize();
4040 sec_fac = sector_size / 512;
4041#ifdef CONFIG_FEATURE_SUN_LABEL
4042 guess_device_type();
4043#endif
4044 heads = cylinders = sectors = 0;
4045 kern_heads = kern_sectors = 0;
4046 pt_heads = pt_sectors = 0;
4047
4048 get_kernel_geometry();
4049 get_partition_table_geometry();
4050
4051 heads = user_heads ? user_heads :
4052 pt_heads ? pt_heads :
4053 kern_heads ? kern_heads : 255;
4054 sectors = user_sectors ? user_sectors :
4055 pt_sectors ? pt_sectors :
4056 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004057 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4058 /* got bytes */
4059 } else {
4060 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004061
4062 if (ioctl(fd, BLKGETSIZE, &longsectors))
4063 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004064 bytes = ((unsigned long long) longsectors) << 9;
4065 }
4066
4067 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004068
4069 sector_offset = 1;
4070 if (dos_compatible_flag)
4071 sector_offset = sectors;
4072
Eric Andersen040f4402003-07-30 08:40:37 +00004073 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004074 if (!cylinders)
4075 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004076}
4077
4078/*
4079 * Read MBR. Returns:
4080 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4081 * 0: found or created label
4082 * 1: I/O error
4083 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004084static int
4085get_boot(enum action what)
4086{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004087 int i;
4088
4089 partitions = 4;
4090
4091 for (i = 0; i < 4; i++) {
4092 struct pte *pe = &ptes[i];
4093
4094 pe->part_table = pt_offset(MBRbuffer, i);
4095 pe->ext_pointer = NULL;
4096 pe->offset = 0;
4097 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004098#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004099 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004100#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004101 }
4102
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004103#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004104 if (what == create_empty_sun && check_sun_label())
4105 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004106#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004107
4108 memset(MBRbuffer, 0, 512);
4109
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004110#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004111 if (what == create_empty_dos)
4112 goto got_dos_table; /* skip reading disk */
4113
4114 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004115 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4116 if (what == try_only)
4117 return 1;
4118 fdisk_fatal(unable_to_open);
4119 } else
4120 printf(_("You will not be able to write "
4121 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004122 }
4123
4124 if (512 != read(fd, MBRbuffer, 512)) {
4125 if (what == try_only)
4126 return 1;
4127 fdisk_fatal(unable_to_read);
4128 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004129#else
4130 if ((fd = open(disk_device, O_RDONLY)) < 0)
4131 return 1;
4132 if (512 != read(fd, MBRbuffer, 512))
4133 return 1;
4134#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004135
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004136 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004137
4138 update_units();
4139
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004140#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004141 if (check_sun_label())
4142 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004143#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004144
4145#ifdef CONFIG_FEATURE_SGI_LABEL
4146 if (check_sgi_label())
4147 return 0;
4148#endif
4149
4150#ifdef CONFIG_FEATURE_AIX_LABEL
4151 if (check_aix_label())
4152 return 0;
4153#endif
4154
4155#ifdef CONFIG_FEATURE_OSF_LABEL
4156 if (check_osf_label()) {
4157 possibly_osf_label = 1;
4158 if (!valid_part_table_flag(MBRbuffer)) {
4159 osf_label = 1;
4160 return 0;
4161 }
4162 printf(_("This disk has both DOS and BSD magic.\n"
4163 "Give the 'b' command to go to BSD mode.\n"));
4164 }
4165#endif
4166
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004167#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004168 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004169#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004170
4171 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004172#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4173 return -1;
4174#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004175 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004176 case fdisk:
4177 fprintf(stderr,
4178 _("Device contains neither a valid DOS "
4179 "partition table, nor Sun, SGI or OSF "
4180 "disklabel\n"));
4181#ifdef __sparc__
4182#ifdef CONFIG_FEATURE_SUN_LABEL
4183 create_sunlabel();
4184#endif
4185#else
4186 create_doslabel();
4187#endif
4188 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004189 case try_only:
4190 return -1;
4191 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004192#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004193 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004194#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004195 break;
4196 default:
4197 fprintf(stderr, _("Internal error\n"));
4198 exit(1);
4199 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004200#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004201 }
4202
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004203#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004204 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004205#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004206 warn_geometry();
4207
4208 for (i = 0; i < 4; i++) {
4209 struct pte *pe = &ptes[i];
4210
Rob Landleyb73451d2006-02-24 16:29:00 +00004211 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004212 if (partitions != 4)
4213 fprintf(stderr, _("Ignoring extra extended "
4214 "partition %d\n"), i + 1);
4215 else
4216 read_extended(i);
4217 }
4218 }
4219
4220 for (i = 3; i < partitions; i++) {
4221 struct pte *pe = &ptes[i];
4222
4223 if (!valid_part_table_flag(pe->sectorbuffer)) {
4224 fprintf(stderr,
4225 _("Warning: invalid flag 0x%04x of partition "
4226 "table %d will be corrected by w(rite)\n"),
4227 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004228#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004229 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004230#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004231 }
4232 }
4233
4234 return 0;
4235}
4236
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004237#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004238/*
4239 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4240 * If the user hits Enter, DFLT is returned.
4241 * Answers like +10 are interpreted as offsets from BASE.
4242 *
4243 * There is no default if DFLT is not between LOW and HIGH.
4244 */
4245static uint
4246read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4247{
4248 uint i;
4249 int default_ok = 1;
4250 static char *ms = NULL;
4251 static int mslen = 0;
4252
4253 if (!ms || strlen(mesg)+100 > mslen) {
4254 mslen = strlen(mesg)+200;
4255 ms = xrealloc(ms,mslen);
4256 }
4257
4258 if (dflt < low || dflt > high)
4259 default_ok = 0;
4260
4261 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004262 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004263 mesg, low, high, dflt);
4264 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004265 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004266
4267 while (1) {
4268 int use_default = default_ok;
4269
4270 /* ask question and read answer */
4271 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004272 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004273 continue;
4274
Eric Andersen84bdea82004-05-19 10:49:17 +00004275 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004276 int minus = (*line_ptr == '-');
4277 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004278
Rob Landleyb73451d2006-02-24 16:29:00 +00004279 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004280
Rob Landleyb73451d2006-02-24 16:29:00 +00004281 while (isdigit(*++line_ptr))
4282 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004283
Rob Landleyb73451d2006-02-24 16:29:00 +00004284 switch (*line_ptr) {
4285 case 'c':
4286 case 'C':
4287 if (!display_in_cyl_units)
4288 i *= heads * sectors;
4289 break;
4290 case 'K':
4291 absolute = 1024;
4292 break;
4293 case 'k':
4294 absolute = 1000;
4295 break;
4296 case 'm':
4297 case 'M':
4298 absolute = 1000000;
4299 break;
4300 case 'g':
4301 case 'G':
4302 absolute = 1000000000;
4303 break;
4304 default:
4305 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004306 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004307 if (absolute) {
4308 unsigned long long bytes;
4309 unsigned long unit;
4310
4311 bytes = (unsigned long long) i * absolute;
4312 unit = sector_size * units_per_sector;
4313 bytes += unit/2; /* round */
4314 bytes /= unit;
4315 i = bytes;
4316 }
4317 if (minus)
4318 i = -i;
4319 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004320 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004321 i = atoi(line_ptr);
4322 while (isdigit(*line_ptr)) {
4323 line_ptr++;
4324 use_default = 0;
4325 }
4326 }
4327 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004328 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004329 if (i >= low && i <= high)
4330 break;
4331 else
4332 printf(_("Value out of range.\n"));
4333 }
4334 return i;
4335}
4336
Rob Landleyb73451d2006-02-24 16:29:00 +00004337static int
4338get_partition(int warn, int max)
4339{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004340 struct pte *pe;
4341 int i;
4342
4343 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4344 pe = &ptes[i];
4345
4346 if (warn) {
4347 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4348#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00004349 || (sun_label &&
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004350 (!sunlabel->partitions[i].num_sectors ||
4351 !sunlabel->infos[i].id))
4352#endif
4353#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00004354 || (sgi_label && (!sgi_get_num_sectors(i)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004355#endif
4356 )
4357 fprintf(stderr,
4358 _("Warning: partition %d has empty type\n"),
4359 i+1);
4360 }
4361 return i;
4362}
4363
4364static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004365get_existing_partition(int warn, int max)
4366{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004367 int pno = -1;
4368 int i;
4369
4370 for (i = 0; i < max; i++) {
4371 struct pte *pe = &ptes[i];
4372 struct partition *p = pe->part_table;
4373
4374 if (p && !is_cleared_partition(p)) {
4375 if (pno >= 0)
4376 goto not_unique;
4377 pno = i;
4378 }
4379 }
4380 if (pno >= 0) {
4381 printf(_("Selected partition %d\n"), pno+1);
4382 return pno;
4383 }
4384 printf(_("No partition is defined yet!\n"));
4385 return -1;
4386
4387 not_unique:
4388 return get_partition(warn, max);
4389}
4390
4391static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004392get_nonexisting_partition(int warn, int max)
4393{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004394 int pno = -1;
4395 int i;
4396
4397 for (i = 0; i < max; i++) {
4398 struct pte *pe = &ptes[i];
4399 struct partition *p = pe->part_table;
4400
4401 if (p && is_cleared_partition(p)) {
4402 if (pno >= 0)
4403 goto not_unique;
4404 pno = i;
4405 }
4406 }
4407 if (pno >= 0) {
4408 printf(_("Selected partition %d\n"), pno+1);
4409 return pno;
4410 }
4411 printf(_("All primary partitions have been defined already!\n"));
4412 return -1;
4413
4414 not_unique:
4415 return get_partition(warn, max);
4416}
4417
4418
4419void change_units(void)
4420{
4421 display_in_cyl_units = !display_in_cyl_units;
4422 update_units();
4423 printf(_("Changing display/entry units to %s\n"),
4424 str_units(PLURAL));
4425}
4426
4427static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004428toggle_active(int i)
4429{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004430 struct pte *pe = &ptes[i];
4431 struct partition *p = pe->part_table;
4432
Rob Landleyb73451d2006-02-24 16:29:00 +00004433 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004434 fprintf(stderr,
4435 _("WARNING: Partition %d is an extended partition\n"),
4436 i + 1);
4437 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4438 pe->changed = 1;
4439}
4440
4441static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004442toggle_dos_compatibility_flag(void)
4443{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004444 dos_compatible_flag = ~dos_compatible_flag;
4445 if (dos_compatible_flag) {
4446 sector_offset = sectors;
4447 printf(_("DOS Compatibility flag is set\n"));
4448 }
4449 else {
4450 sector_offset = 1;
4451 printf(_("DOS Compatibility flag is not set\n"));
4452 }
4453}
4454
4455static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004456delete_partition(int i)
4457{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004458 struct pte *pe = &ptes[i];
4459 struct partition *p = pe->part_table;
4460 struct partition *q = pe->ext_pointer;
4461
4462/* Note that for the fifth partition (i == 4) we don't actually
4463 * decrement partitions.
4464 */
4465
4466 if (warn_geometry())
4467 return; /* C/H/S not set */
4468 pe->changed = 1;
4469
4470#ifdef CONFIG_FEATURE_SUN_LABEL
4471 if (sun_label) {
4472 sun_delete_partition(i);
4473 return;
4474 }
4475#endif
4476#ifdef CONFIG_FEATURE_SGI_LABEL
4477 if (sgi_label) {
4478 sgi_delete_partition(i);
4479 return;
4480 }
4481#endif
4482
4483 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004484 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004485 partitions = 4;
4486 ptes[ext_index].ext_pointer = NULL;
4487 extended_offset = 0;
4488 }
4489 clear_partition(p);
4490 return;
4491 }
4492
4493 if (!q->sys_ind && i > 4) {
4494 /* the last one in the chain - just delete */
4495 --partitions;
4496 --i;
4497 clear_partition(ptes[i].ext_pointer);
4498 ptes[i].changed = 1;
4499 } else {
4500 /* not the last one - further ones will be moved down */
4501 if (i > 4) {
4502 /* delete this link in the chain */
4503 p = ptes[i-1].ext_pointer;
4504 *p = *q;
4505 set_start_sect(p, get_start_sect(q));
4506 set_nr_sects(p, get_nr_sects(q));
4507 ptes[i-1].changed = 1;
4508 } else if (partitions > 5) { /* 5 will be moved to 4 */
4509 /* the first logical in a longer chain */
4510 pe = &ptes[5];
4511
4512 if (pe->part_table) /* prevent SEGFAULT */
4513 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004514 get_partition_start(pe) -
4515 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004516 pe->offset = extended_offset;
4517 pe->changed = 1;
4518 }
4519
4520 if (partitions > 5) {
4521 partitions--;
4522 while (i < partitions) {
4523 ptes[i] = ptes[i+1];
4524 i++;
4525 }
4526 } else
4527 /* the only logical: clear only */
4528 clear_partition(ptes[i].part_table);
4529 }
4530}
4531
4532static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004533change_sysid(void)
4534{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004535 int i, sys, origsys;
4536 struct partition *p;
4537
Eric Andersen040f4402003-07-30 08:40:37 +00004538#ifdef CONFIG_FEATURE_SGI_LABEL
4539 /* If sgi_label then don't use get_existing_partition,
4540 let the user select a partition, since get_existing_partition()
4541 only works for Linux like partition tables. */
4542 if (!sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004543 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004544 } else {
4545 i = get_partition(0, partitions);
4546 }
4547#else
4548 i = get_existing_partition(0, partitions);
4549#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004550 if (i == -1)
4551 return;
4552 p = ptes[i].part_table;
4553 origsys = sys = get_sysid(i);
4554
4555 /* if changing types T to 0 is allowed, then
4556 the reverse change must be allowed, too */
4557 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4558 printf(_("Partition %d does not exist yet!\n"), i + 1);
4559 else while (1) {
4560 sys = read_hex (get_sys_types());
4561
4562 if (!sys && !sgi_label && !sun_label) {
4563 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004564 "(but not to Linux). Having partitions of\n"
4565 "type 0 is probably unwise. You can delete\n"
4566 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004567 /* break; */
4568 }
4569
4570 if (!sun_label && !sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004571 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004572 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004573 " an extended one or vice versa\n"
4574 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004575 break;
4576 }
4577 }
4578
4579 if (sys < 256) {
4580#ifdef CONFIG_FEATURE_SUN_LABEL
4581 if (sun_label && i == 2 && sys != WHOLE_DISK)
4582 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004583 "as Whole disk (5),\n"
4584 "as SunOS/Solaris expects it and "
4585 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004586#endif
4587#ifdef CONFIG_FEATURE_SGI_LABEL
4588 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4589 || (i == 8 && sys != 0)))
4590 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004591 "as volume header (0),\nand "
4592 "partition 11 as entire volume (6)"
4593 "as IRIX expects it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004594#endif
4595 if (sys == origsys)
4596 break;
4597#ifdef CONFIG_FEATURE_SUN_LABEL
4598 if (sun_label) {
4599 sun_change_sysid(i, sys);
4600 } else
4601#endif
4602#ifdef CONFIG_FEATURE_SGI_LABEL
4603 if (sgi_label) {
4604 sgi_change_sysid(i, sys);
4605 } else
4606#endif
4607 p->sys_ind = sys;
Rob Landleyb73451d2006-02-24 16:29:00 +00004608 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004609 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004610 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004611 ptes[i].changed = 1;
4612 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004613 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004614 dos_changed = 1;
4615 break;
4616 }
4617 }
4618}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004619#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4620
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004621
4622/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4623 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4624 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4625 * Lubkin Oct. 1991). */
4626
Rob Landleyb73451d2006-02-24 16:29:00 +00004627static void
4628long2chs(ulong ls, uint *c, uint *h, uint *s)
4629{
4630 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004631
4632 *c = ls / spc;
4633 ls = ls % spc;
4634 *h = ls / sectors;
4635 *s = ls % sectors + 1; /* sectors count from 1 */
4636}
4637
Rob Landleyb73451d2006-02-24 16:29:00 +00004638static void
4639check_consistency(const struct partition *p, int partition)
4640{
4641 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4642 uint pec, peh, pes; /* physical ending c, h, s */
4643 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4644 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004645
4646 if (!heads || !sectors || (partition >= 4))
4647 return; /* do not check extended partitions */
4648
4649/* physical beginning c, h, s */
4650 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4651 pbh = p->head;
4652 pbs = p->sector & 0x3f;
4653
4654/* physical ending c, h, s */
4655 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4656 peh = p->end_head;
4657 pes = p->end_sector & 0x3f;
4658
4659/* compute logical beginning (c, h, s) */
4660 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4661
4662/* compute logical ending (c, h, s) */
4663 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4664
4665/* Same physical / logical beginning? */
4666 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4667 printf(_("Partition %d has different physical/logical "
4668 "beginnings (non-Linux?):\n"), partition + 1);
4669 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4670 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4671 }
4672
4673/* Same physical / logical ending? */
4674 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4675 printf(_("Partition %d has different physical/logical "
4676 "endings:\n"), partition + 1);
4677 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4678 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4679 }
4680
4681#if 0
4682/* Beginning on cylinder boundary? */
4683 if (pbh != !pbc || pbs != 1) {
4684 printf(_("Partition %i does not start on cylinder "
4685 "boundary:\n"), partition + 1);
4686 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4687 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4688 }
4689#endif
4690
4691/* Ending on cylinder boundary? */
4692 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004693 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004694 partition + 1);
4695#if 0
4696 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4697 printf(_("should be (%d, %d, %d)\n"),
4698 pec, heads - 1, sectors);
4699#endif
4700 }
4701}
4702
4703static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004704list_disk_geometry(void)
4705{
Eric Andersen040f4402003-07-30 08:40:37 +00004706 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004707 long megabytes = bytes/1000000;
4708
4709 if (megabytes < 10000)
4710 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004711 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004712 else
4713 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004714 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004715 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004716 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004717 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004718 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004719 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004720 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004721 str_units(PLURAL),
4722 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004723}
4724
4725/*
4726 * Check whether partition entries are ordered by their starting positions.
4727 * Return 0 if OK. Return i if partition i should have been earlier.
4728 * Two separate checks: primary and logical partitions.
4729 */
4730static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004731wrong_p_order(int *prev)
4732{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004733 const struct pte *pe;
4734 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004735 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004736 int i, last_i = 0;
4737
4738 for (i = 0 ; i < partitions; i++) {
4739 if (i == 4) {
4740 last_i = 4;
4741 last_p_start_pos = 0;
4742 }
4743 pe = &ptes[i];
4744 if ((p = pe->part_table)->sys_ind) {
4745 p_start_pos = get_partition_start(pe);
4746
4747 if (last_p_start_pos > p_start_pos) {
4748 if (prev)
4749 *prev = last_i;
4750 return i;
4751 }
4752
4753 last_p_start_pos = p_start_pos;
4754 last_i = i;
4755 }
4756 }
4757 return 0;
4758}
4759
4760#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4761/*
4762 * Fix the chain of logicals.
4763 * extended_offset is unchanged, the set of sectors used is unchanged
4764 * The chain is sorted so that sectors increase, and so that
4765 * starting sectors increase.
4766 *
4767 * After this it may still be that cfdisk doesnt like the table.
4768 * (This is because cfdisk considers expanded parts, from link to
4769 * end of partition, and these may still overlap.)
4770 * Now
4771 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4772 * may help.
4773 */
4774static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004775fix_chain_of_logicals(void)
4776{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004777 int j, oj, ojj, sj, sjj;
4778 struct partition *pj,*pjj,tmp;
4779
4780 /* Stage 1: sort sectors but leave sector of part 4 */
4781 /* (Its sector is the global extended_offset.) */
4782 stage1:
4783 for (j = 5; j < partitions-1; j++) {
4784 oj = ptes[j].offset;
4785 ojj = ptes[j+1].offset;
4786 if (oj > ojj) {
4787 ptes[j].offset = ojj;
4788 ptes[j+1].offset = oj;
4789 pj = ptes[j].part_table;
4790 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4791 pjj = ptes[j+1].part_table;
4792 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4793 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004794 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004795 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004796 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004797 goto stage1;
4798 }
4799 }
4800
4801 /* Stage 2: sort starting sectors */
4802 stage2:
4803 for (j = 4; j < partitions-1; j++) {
4804 pj = ptes[j].part_table;
4805 pjj = ptes[j+1].part_table;
4806 sj = get_start_sect(pj);
4807 sjj = get_start_sect(pjj);
4808 oj = ptes[j].offset;
4809 ojj = ptes[j+1].offset;
4810 if (oj+sj > ojj+sjj) {
4811 tmp = *pj;
4812 *pj = *pjj;
4813 *pjj = tmp;
4814 set_start_sect(pj, ojj+sjj-oj);
4815 set_start_sect(pjj, oj+sj-ojj);
4816 goto stage2;
4817 }
4818 }
4819
4820 /* Probably something was changed */
4821 for (j = 4; j < partitions; j++)
4822 ptes[j].changed = 1;
4823}
4824
4825
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004826static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004827fix_partition_table_order(void)
4828{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004829 struct pte *pei, *pek;
4830 int i,k;
4831
4832 if (!wrong_p_order(NULL)) {
4833 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4834 return;
4835 }
4836
4837 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4838 /* partition i should have come earlier, move it */
4839 /* We have to move data in the MBR */
4840 struct partition *pi, *pk, *pe, pbuf;
4841 pei = &ptes[i];
4842 pek = &ptes[k];
4843
4844 pe = pei->ext_pointer;
4845 pei->ext_pointer = pek->ext_pointer;
4846 pek->ext_pointer = pe;
4847
4848 pi = pei->part_table;
4849 pk = pek->part_table;
4850
4851 memmove(&pbuf, pi, sizeof(struct partition));
4852 memmove(pi, pk, sizeof(struct partition));
4853 memmove(pk, &pbuf, sizeof(struct partition));
4854
4855 pei->changed = pek->changed = 1;
4856 }
4857
4858 if (i)
4859 fix_chain_of_logicals();
4860
4861 printf("Done.\n");
4862
4863}
4864#endif
4865
4866static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004867list_table(int xtra)
4868{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004869 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004870 int i, w;
4871
4872#ifdef CONFIG_FEATURE_SUN_LABEL
4873 if (sun_label) {
4874 sun_list_table(xtra);
4875 return;
4876 }
4877#endif
4878
4879#ifdef CONFIG_FEATURE_SGI_LABEL
4880 if (sgi_label) {
4881 sgi_list_table(xtra);
4882 return;
4883 }
4884#endif
4885
4886 list_disk_geometry();
4887
4888#ifdef CONFIG_FEATURE_OSF_LABEL
4889 if (osf_label) {
4890 xbsd_print_disklabel(xtra);
4891 return;
4892 }
4893#endif
4894
4895 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4896 but if the device name ends in a digit, say /dev/foo1,
4897 then the partition is called /dev/foo1p3. */
4898 w = strlen(disk_device);
4899 if (w && isdigit(disk_device[w-1]))
4900 w++;
4901 if (w < 5)
4902 w = 5;
4903
4904 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004905 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004906
4907 for (i = 0; i < partitions; i++) {
4908 const struct pte *pe = &ptes[i];
4909
4910 p = pe->part_table;
4911 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004912 off_t psects = get_nr_sects(p);
4913 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004914 unsigned int podd = 0;
4915
4916 if (sector_size < 1024) {
4917 pblocks /= (1024 / sector_size);
4918 podd = psects % (1024 / sector_size);
4919 }
4920 if (sector_size > 1024)
4921 pblocks *= (sector_size / 1024);
4922 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004923 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004924 partname(disk_device, i+1, w+2),
4925/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4926 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004927/* start */ (unsigned long long) cround(get_partition_start(pe)),
4928/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004929 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004930/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004931/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004932/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004933 check_consistency(p, i);
4934 }
4935 }
4936
4937 /* Is partition table in disk order? It need not be, but... */
4938 /* partition table entries are not checked for correct order if this
4939 is a sgi, sun or aix labeled disk... */
4940 if (dos_label && wrong_p_order(NULL)) {
4941 printf(_("\nPartition table entries are not in disk order\n"));
4942 }
4943}
4944
4945#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4946static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004947x_list_table(int extend)
4948{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004949 const struct pte *pe;
4950 const struct partition *p;
4951 int i;
4952
4953 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4954 disk_device, heads, sectors, cylinders);
4955 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4956 for (i = 0 ; i < partitions; i++) {
4957 pe = &ptes[i];
4958 p = (extend ? pe->ext_pointer : pe->part_table);
4959 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004960 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004961 i + 1, p->boot_ind, p->head,
4962 sector(p->sector),
4963 cylinder(p->sector, p->cyl), p->end_head,
4964 sector(p->end_sector),
4965 cylinder(p->end_sector, p->end_cyl),
4966 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4967 if (p->sys_ind)
4968 check_consistency(p, i);
4969 }
4970 }
4971}
4972#endif
4973
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004974#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004975static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004976fill_bounds(off_t *first, off_t *last)
4977{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004978 int i;
4979 const struct pte *pe = &ptes[0];
4980 const struct partition *p;
4981
4982 for (i = 0; i < partitions; pe++,i++) {
4983 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004984 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004985 first[i] = 0xffffffff;
4986 last[i] = 0;
4987 } else {
4988 first[i] = get_partition_start(pe);
4989 last[i] = first[i] + get_nr_sects(p) - 1;
4990 }
4991 }
4992}
4993
4994static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004995check(int n, uint h, uint s, uint c, off_t start)
4996{
Eric Andersend9261492004-06-28 23:50:31 +00004997 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004998
4999 real_s = sector(s) - 1;
5000 real_c = cylinder(s, c);
5001 total = (real_c * sectors + real_s) * heads + h;
5002 if (!total)
5003 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
5004 if (h >= heads)
5005 fprintf(stderr,
5006 _("Partition %d: head %d greater than maximum %d\n"),
5007 n, h + 1, heads);
5008 if (real_s >= sectors)
5009 fprintf(stderr, _("Partition %d: sector %d greater than "
5010 "maximum %d\n"), n, s, sectors);
5011 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00005012 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
5013 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005014 if (cylinders <= 1024 && start != total)
5015 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00005016 _("Partition %d: previous sectors %llu disagrees with "
5017 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005018}
5019
5020static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005021verify(void)
5022{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005023 int i, j;
5024 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00005025 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005026 struct partition *p;
5027
5028 if (warn_geometry())
5029 return;
5030
5031#ifdef CONFIG_FEATURE_SUN_LABEL
5032 if (sun_label) {
5033 verify_sun();
5034 return;
5035 }
5036#endif
5037#ifdef CONFIG_FEATURE_SGI_LABEL
5038 if (sgi_label) {
5039 verify_sgi(1);
5040 return;
5041 }
5042#endif
5043
5044 fill_bounds(first, last);
5045 for (i = 0; i < partitions; i++) {
5046 struct pte *pe = &ptes[i];
5047
5048 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005049 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005050 check_consistency(p, i);
5051 if (get_partition_start(pe) < first[i])
5052 printf(_("Warning: bad start-of-data in "
5053 "partition %d\n"), i + 1);
5054 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5055 last[i]);
5056 total += last[i] + 1 - first[i];
5057 for (j = 0; j < i; j++)
5058 if ((first[i] >= first[j] && first[i] <= last[j])
5059 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5060 printf(_("Warning: partition %d overlaps "
5061 "partition %d.\n"), j + 1, i + 1);
5062 total += first[i] >= first[j] ?
5063 first[i] : first[j];
5064 total -= last[i] <= last[j] ?
5065 last[i] : last[j];
5066 }
5067 }
5068 }
5069
5070 if (extended_offset) {
5071 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005072 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005073 get_nr_sects(pex->part_table) - 1;
5074
5075 for (i = 4; i < partitions; i++) {
5076 total++;
5077 p = ptes[i].part_table;
5078 if (!p->sys_ind) {
5079 if (i != 4 || i + 1 < partitions)
5080 printf(_("Warning: partition %d "
5081 "is empty\n"), i + 1);
5082 }
5083 else if (first[i] < extended_offset ||
5084 last[i] > e_last)
5085 printf(_("Logical partition %d not entirely in "
5086 "partition %d\n"), i + 1, ext_index + 1);
5087 }
5088 }
5089
5090 if (total > heads * sectors * cylinders)
5091 printf(_("Total allocated sectors %d greater than the maximum "
5092 "%d\n"), total, heads * sectors * cylinders);
5093 else if ((total = heads * sectors * cylinders - total) != 0)
5094 printf(_("%d unallocated sectors\n"), total);
5095}
5096
5097static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005098add_partition(int n, int sys)
5099{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005100 char mesg[256]; /* 48 does not suffice in Japanese */
5101 int i, readed = 0;
5102 struct partition *p = ptes[n].part_table;
5103 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005104 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005105 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005106 first[partitions], last[partitions];
5107
5108 if (p && p->sys_ind) {
5109 printf(_("Partition %d is already defined. Delete "
5110 "it before re-adding it.\n"), n + 1);
5111 return;
5112 }
5113 fill_bounds(first, last);
5114 if (n < 4) {
5115 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005116 if (display_in_cyl_units || !total_number_of_sectors)
5117 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005118 else
Eric Andersen040f4402003-07-30 08:40:37 +00005119 llimit = total_number_of_sectors - 1;
5120 limit = llimit;
5121 if (limit != llimit)
5122 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005123 if (extended_offset) {
5124 first[ext_index] = extended_offset;
5125 last[ext_index] = get_start_sect(q) +
5126 get_nr_sects(q) - 1;
5127 }
5128 } else {
5129 start = extended_offset + sector_offset;
5130 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5131 }
5132 if (display_in_cyl_units)
5133 for (i = 0; i < partitions; i++)
5134 first[i] = (cround(first[i]) - 1) * units_per_sector;
5135
5136 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5137 do {
5138 temp = start;
5139 for (i = 0; i < partitions; i++) {
5140 int lastplusoff;
5141
5142 if (start == ptes[i].offset)
5143 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005144 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005145 if (start >= first[i] && start <= lastplusoff)
5146 start = lastplusoff + 1;
5147 }
5148 if (start > limit)
5149 break;
5150 if (start >= temp+units_per_sector && readed) {
Eric Andersend9261492004-06-28 23:50:31 +00005151 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005152 temp = start;
5153 readed = 0;
5154 }
5155 if (!readed && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005156 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005157
5158 saved_start = start;
5159 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5160 0, mesg);
5161 if (display_in_cyl_units) {
5162 start = (start - 1) * units_per_sector;
5163 if (start < saved_start) start = saved_start;
5164 }
5165 readed = 1;
5166 }
5167 } while (start != temp || !readed);
5168 if (n > 4) { /* NOT for fifth partition */
5169 struct pte *pe = &ptes[n];
5170
5171 pe->offset = start - sector_offset;
5172 if (pe->offset == extended_offset) { /* must be corrected */
5173 pe->offset++;
5174 if (sector_offset == 1)
5175 start++;
5176 }
5177 }
5178
5179 for (i = 0; i < partitions; i++) {
5180 struct pte *pe = &ptes[i];
5181
5182 if (start < pe->offset && limit >= pe->offset)
5183 limit = pe->offset - 1;
5184 if (start < first[i] && limit >= first[i])
5185 limit = first[i] - 1;
5186 }
5187 if (start > limit) {
5188 printf(_("No free sectors available\n"));
5189 if (n > 4)
5190 partitions--;
5191 return;
5192 }
5193 if (cround(start) == cround(limit)) {
5194 stop = limit;
5195 } else {
5196 snprintf(mesg, sizeof(mesg),
5197 _("Last %s or +size or +sizeM or +sizeK"),
5198 str_units(SINGULAR));
5199 stop = read_int(cround(start), cround(limit), cround(limit),
5200 cround(start), mesg);
5201 if (display_in_cyl_units) {
5202 stop = stop * units_per_sector - 1;
5203 if (stop >limit)
5204 stop = limit;
5205 }
5206 }
5207
5208 set_partition(n, 0, start, stop, sys);
5209 if (n > 4)
5210 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5211
Rob Landleyb73451d2006-02-24 16:29:00 +00005212 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005213 struct pte *pe4 = &ptes[4];
5214 struct pte *pen = &ptes[n];
5215
5216 ext_index = n;
5217 pen->ext_pointer = p;
5218 pe4->offset = extended_offset = start;
5219 pe4->sectorbuffer = xcalloc(1, sector_size);
5220 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5221 pe4->ext_pointer = pe4->part_table + 1;
5222 pe4->changed = 1;
5223 partitions = 5;
5224 }
5225}
5226
5227static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005228add_logical(void)
5229{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005230 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5231 struct pte *pe = &ptes[partitions];
5232
5233 pe->sectorbuffer = xcalloc(1, sector_size);
5234 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5235 pe->ext_pointer = pe->part_table + 1;
5236 pe->offset = 0;
5237 pe->changed = 1;
5238 partitions++;
5239 }
5240 add_partition(partitions - 1, LINUX_NATIVE);
5241}
5242
5243static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005244new_partition(void)
5245{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005246 int i, free_primary = 0;
5247
5248 if (warn_geometry())
5249 return;
5250
5251#ifdef CONFIG_FEATURE_SUN_LABEL
5252 if (sun_label) {
5253 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5254 return;
5255 }
5256#endif
5257#ifdef CONFIG_FEATURE_SGI_LABEL
5258 if (sgi_label) {
5259 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5260 return;
5261 }
5262#endif
5263#ifdef CONFIG_FEATURE_AIX_LABEL
5264 if (aix_label) {
5265 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5266 "\n\tIf you want to add DOS-type partitions, create"
5267 "\n\ta new empty DOS partition table first. (Use o.)"
5268 "\n\tWARNING: "
5269 "This will destroy the present disk contents.\n"));
5270 return;
5271 }
5272#endif
5273
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005274 for (i = 0; i < 4; i++)
5275 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005276
Rob Landleyb73451d2006-02-24 16:29:00 +00005277 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005278 printf(_("The maximum number of partitions has been created\n"));
5279 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005280 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005281
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005282 if (!free_primary) {
5283 if (extended_offset)
5284 add_logical();
5285 else
5286 printf(_("You must delete some partition and add "
5287 "an extended partition first\n"));
5288 } else {
5289 char c, line[LINE_LENGTH];
5290 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5291 "partition (1-4)\n",
5292 "Command action", (extended_offset ?
5293 "l logical (5 or over)" : "e extended"));
5294 while (1) {
5295 if ((c = read_char(line)) == 'p' || c == 'P') {
5296 i = get_nonexisting_partition(0, 4);
5297 if (i >= 0)
5298 add_partition(i, LINUX_NATIVE);
5299 return;
5300 }
5301 else if (c == 'l' && extended_offset) {
5302 add_logical();
5303 return;
5304 }
5305 else if (c == 'e' && !extended_offset) {
5306 i = get_nonexisting_partition(0, 4);
5307 if (i >= 0)
5308 add_partition(i, EXTENDED);
5309 return;
5310 }
5311 else
5312 printf(_("Invalid partition number "
5313 "for type `%c'\n"), c);
5314 }
5315 }
5316}
5317
5318static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005319write_table(void)
5320{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005321 int i;
5322
5323 if (dos_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005324 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005325 if (ptes[i].changed)
5326 ptes[3].changed = 1;
5327 for (i = 3; i < partitions; i++) {
5328 struct pte *pe = &ptes[i];
5329
5330 if (pe->changed) {
5331 write_part_table_flag(pe->sectorbuffer);
5332 write_sector(pe->offset, pe->sectorbuffer);
5333 }
5334 }
5335 }
5336#ifdef CONFIG_FEATURE_SGI_LABEL
5337 else if (sgi_label) {
5338 /* no test on change? the printf below might be mistaken */
5339 sgi_write_table();
5340 }
5341#endif
5342#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00005343 else if (sun_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005344 int needw = 0;
5345
Rob Landleyb73451d2006-02-24 16:29:00 +00005346 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005347 if (ptes[i].changed)
5348 needw = 1;
5349 if (needw)
5350 sun_write_table();
5351 }
5352#endif
5353
5354 printf(_("The partition table has been altered!\n\n"));
5355 reread_partition_table(1);
5356}
5357
Rob Landleyb73451d2006-02-24 16:29:00 +00005358static void
5359reread_partition_table(int leave)
5360{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005361 int error = 0;
5362 int i;
5363
5364 printf(_("Calling ioctl() to re-read partition table.\n"));
5365 sync();
5366 sleep(2);
5367 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5368 error = errno;
5369 } else {
5370 /* some kernel versions (1.2.x) seem to have trouble
5371 rereading the partition table, but if asked to do it
5372 twice, the second time works. - biro@yggdrasil.com */
5373 sync();
5374 sleep(2);
5375 if ((i = ioctl(fd, BLKRRPART)) != 0)
5376 error = errno;
5377 }
5378
5379 if (i) {
5380 printf(_("\nWARNING: Re-reading the partition table "
5381 "failed with error %d: %s.\n"
5382 "The kernel still uses the old table.\n"
5383 "The new table will be used "
5384 "at the next reboot.\n"),
5385 error, strerror(error));
5386 }
5387
5388 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005389 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005390 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5391 "partitions, please see the fdisk manual page for additional\n"
5392 "information.\n"));
5393
5394 if (leave) {
5395 close(fd);
5396
5397 printf(_("Syncing disks.\n"));
5398 sync();
5399 sleep(4); /* for sync() */
5400 exit(!!i);
5401 }
5402}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005403#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005404
5405#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5406#define MAX_PER_LINE 16
5407static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005408print_buffer(char *pbuffer)
5409{
5410 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005411
5412 for (i = 0, l = 0; i < sector_size; i++, l++) {
5413 if (l == 0)
5414 printf("0x%03X:", i);
5415 printf(" %02X", (unsigned char) pbuffer[i]);
5416 if (l == MAX_PER_LINE - 1) {
5417 printf("\n");
5418 l = -1;
5419 }
5420 }
5421 if (l > 0)
5422 printf("\n");
5423 printf("\n");
5424}
5425
5426
5427static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005428print_raw(void)
5429{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005430 int i;
5431
5432 printf(_("Device: %s\n"), disk_device);
5433#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5434 if (sun_label || sgi_label)
5435 print_buffer(MBRbuffer);
5436 else
5437#endif
5438 for (i = 3; i < partitions; i++)
5439 print_buffer(ptes[i].sectorbuffer);
5440}
5441
5442static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005443move_begin(int i)
5444{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005445 struct pte *pe = &ptes[i];
5446 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005447 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005448
5449 if (warn_geometry())
5450 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005451 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005452 printf(_("Partition %d has no data area\n"), i + 1);
5453 return;
5454 }
5455 first = get_partition_start(pe);
5456 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005457 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005458
5459 if (new != get_nr_sects(p)) {
5460 first = get_nr_sects(p) + get_start_sect(p) - new;
5461 set_nr_sects(p, first);
5462 set_start_sect(p, new);
5463 pe->changed = 1;
5464 }
5465}
5466
5467static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005468xselect(void)
5469{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005470 char c;
5471
Rob Landleyb73451d2006-02-24 16:29:00 +00005472 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005473 putchar('\n');
5474 c = tolower(read_char(_("Expert command (m for help): ")));
5475 switch (c) {
5476 case 'a':
5477#ifdef CONFIG_FEATURE_SUN_LABEL
5478 if (sun_label)
5479 sun_set_alt_cyl();
5480#endif
5481 break;
5482 case 'b':
5483 if (dos_label)
5484 move_begin(get_partition(0, partitions));
5485 break;
5486 case 'c':
5487 user_cylinders = cylinders =
5488 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005489 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005490#ifdef CONFIG_FEATURE_SUN_LABEL
5491 if (sun_label)
5492 sun_set_ncyl(cylinders);
5493#endif
5494 if (dos_label)
5495 warn_cylinders();
5496 break;
5497 case 'd':
5498 print_raw();
5499 break;
5500 case 'e':
5501#ifdef CONFIG_FEATURE_SGI_LABEL
5502 if (sgi_label)
5503 sgi_set_xcyl();
5504 else
5505#endif
5506#ifdef CONFIG_FEATURE_SUN_LABEL
5507 if (sun_label)
5508 sun_set_xcyl();
5509 else
5510#endif
5511 if (dos_label)
5512 x_list_table(1);
5513 break;
5514 case 'f':
5515 if (dos_label)
5516 fix_partition_table_order();
5517 break;
5518 case 'g':
5519#ifdef CONFIG_FEATURE_SGI_LABEL
5520 create_sgilabel();
5521#endif
5522 break;
5523 case 'h':
5524 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005525 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005526 update_units();
5527 break;
5528 case 'i':
5529#ifdef CONFIG_FEATURE_SUN_LABEL
5530 if (sun_label)
5531 sun_set_ilfact();
5532#endif
5533 break;
5534 case 'o':
5535#ifdef CONFIG_FEATURE_SUN_LABEL
5536 if (sun_label)
5537 sun_set_rspeed();
5538#endif
5539 break;
5540 case 'p':
5541#ifdef CONFIG_FEATURE_SUN_LABEL
5542 if (sun_label)
5543 list_table(1);
5544 else
5545#endif
5546 x_list_table(0);
5547 break;
5548 case 'q':
5549 close(fd);
5550 printf("\n");
5551 exit(0);
5552 case 'r':
5553 return;
5554 case 's':
5555 user_sectors = sectors = read_int(1, sectors, 63, 0,
5556 _("Number of sectors"));
5557 if (dos_compatible_flag) {
5558 sector_offset = sectors;
5559 fprintf(stderr, _("Warning: setting "
5560 "sector offset for DOS "
5561 "compatiblity\n"));
5562 }
5563 update_units();
5564 break;
5565 case 'v':
5566 verify();
5567 break;
5568 case 'w':
5569 write_table(); /* does not return */
5570 break;
5571 case 'y':
5572#ifdef CONFIG_FEATURE_SUN_LABEL
5573 if (sun_label)
5574 sun_set_pcylcount();
5575#endif
5576 break;
5577 default:
5578 xmenu();
5579 }
5580 }
5581}
5582#endif /* ADVANCED mode */
5583
5584static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005585is_ide_cdrom_or_tape(const char *device)
5586{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005587 FILE *procf;
5588 char buf[100];
5589 struct stat statbuf;
5590 int is_ide = 0;
5591
5592 /* No device was given explicitly, and we are trying some
5593 likely things. But opening /dev/hdc may produce errors like
5594 "hdc: tray open or drive not ready"
5595 if it happens to be a CD-ROM drive. It even happens that
5596 the process hangs on the attempt to read a music CD.
5597 So try to be careful. This only works since 2.1.73. */
5598
5599 if (strncmp("/dev/hd", device, 7))
5600 return 0;
5601
5602 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5603 procf = fopen(buf, "r");
5604 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5605 is_ide = (!strncmp(buf, "cdrom", 5) ||
5606 !strncmp(buf, "tape", 4));
5607 else
5608 /* Now when this proc file does not exist, skip the
5609 device when it is read-only. */
5610 if (stat(device, &statbuf) == 0)
5611 is_ide = ((statbuf.st_mode & 0222) == 0);
5612
5613 if (procf)
5614 fclose(procf);
5615 return is_ide;
5616}
5617
5618static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005619try(const char *device, int user_specified)
5620{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005621 int gb;
5622
5623 disk_device = device;
5624 if (setjmp(listingbuf))
5625 return;
5626 if (!user_specified)
5627 if (is_ide_cdrom_or_tape(device))
5628 return;
5629 if ((fd = open(disk_device, type_open)) >= 0) {
5630 gb = get_boot(try_only);
5631 if (gb > 0) { /* I/O error */
5632 close(fd);
5633 } else if (gb < 0) { /* no DOS signature */
5634 list_disk_geometry();
5635 if (aix_label)
5636 return;
5637#ifdef CONFIG_FEATURE_OSF_LABEL
5638 if (btrydev(device) < 0)
5639#endif
5640 fprintf(stderr,
5641 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005642 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005643 close(fd);
5644 } else {
5645 close(fd);
5646 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005647#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005648 if (!sun_label && partitions > 4)
5649 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005650#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005651 }
5652 } else {
5653 /* Ignore other errors, since we try IDE
5654 and SCSI hard disks which may not be
5655 installed on the system. */
5656 if (errno == EACCES) {
5657 fprintf(stderr, _("Cannot open %s\n"), device);
5658 return;
5659 }
5660 }
5661}
5662
5663/* for fdisk -l: try all things in /proc/partitions
5664 that look like a partition name (do not end in a digit) */
5665static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005666tryprocpt(void)
5667{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005668 FILE *procpt;
5669 char line[100], ptname[100], devname[120], *s;
5670 int ma, mi, sz;
5671
Manuel Novoa III cad53642003-03-19 09:13:01 +00005672 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005673
5674 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005675 if (sscanf(line, " %d %d %d %[^\n ]",
5676 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005677 continue;
5678 for (s = ptname; *s; s++);
5679 if (isdigit(s[-1]))
5680 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005681 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005682 try(devname, 0);
5683 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005684#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005685 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005686#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005687}
5688
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005689#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005690static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005691unknown_command(int c)
5692{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005693 printf(_("%c: unknown command\n"), c);
5694}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005695#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005696
Rob Landleyb73451d2006-02-24 16:29:00 +00005697int fdisk_main(int argc, char **argv)
5698{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005699 int c;
5700#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5701 int optl = 0;
5702#endif
5703#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5704 int opts = 0;
5705#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005706 /*
5707 * Calls:
5708 * fdisk -v
5709 * fdisk -l [-b sectorsize] [-u] device ...
5710 * fdisk -s [partition] ...
5711 * fdisk [-b sectorsize] [-u] device
5712 *
5713 * Options -C, -H, -S set the geometry.
5714 *
5715 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005716 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5717#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5718 "s"
5719#endif
5720 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005721 switch (c) {
5722 case 'b':
5723 /* Ugly: this sector size is really per device,
5724 so cannot be combined with multiple disks,
5725 and te same goes for the C/H/S options.
5726 */
5727 sector_size = atoi(optarg);
5728 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005729 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005730 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005731 sector_offset = 2;
5732 user_set_sector_size = 1;
5733 break;
5734 case 'C':
5735 user_cylinders = atoi(optarg);
5736 break;
5737 case 'H':
5738 user_heads = atoi(optarg);
5739 if (user_heads <= 0 || user_heads >= 256)
5740 user_heads = 0;
5741 break;
5742 case 'S':
5743 user_sectors = atoi(optarg);
5744 if (user_sectors <= 0 || user_sectors >= 64)
5745 user_sectors = 0;
5746 break;
5747 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005748#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005749 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005750#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005751 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005752#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005753 case 's':
5754 opts = 1;
5755 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005756#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005757 case 'u':
5758 display_in_cyl_units = 0;
5759 break;
5760 case 'V':
5761 case 'v':
5762 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5763 return 0;
5764 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005765 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005766 }
5767 }
5768
5769#if 0
5770 printf(_("This kernel finds the sector size itself - "
5771 "-b option ignored\n"));
5772#else
5773 if (user_set_sector_size && argc-optind != 1)
5774 printf(_("Warning: the -b (set sector size) option should"
5775 " be used with one specified device\n"));
5776#endif
5777
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005778#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005779 if (optl) {
5780 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005781#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005782 type_open = O_RDONLY;
5783 if (argc > optind) {
5784 int k;
5785#if __GNUC__
5786 /* avoid gcc warning:
5787 variable `k' might be clobbered by `longjmp' */
5788 (void)&k;
5789#endif
5790 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005791 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005792 try(argv[k], 1);
5793 } else {
5794 /* we no longer have default device names */
5795 /* but, we can use /proc/partitions instead */
5796 tryprocpt();
5797 }
5798 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005799#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005800 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005801#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005802
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005803#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005804 if (opts) {
5805 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005806 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005807
5808 nowarn = 1;
5809 type_open = O_RDONLY;
5810
5811 opts = argc - optind;
5812 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005813 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005814
5815 for (j = optind; j < argc; j++) {
5816 disk_device = argv[j];
5817 if ((fd = open(disk_device, type_open)) < 0)
5818 fdisk_fatal(unable_to_open);
5819 if (ioctl(fd, BLKGETSIZE, &size))
5820 fdisk_fatal(ioctl_error);
5821 close(fd);
5822 if (opts == 1)
5823 printf("%ld\n", size/2);
5824 else
5825 printf("%s: %ld\n", argv[j], size/2);
5826 }
5827 return 0;
5828 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005829#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005830
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005831#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005832 if (argc-optind == 1)
5833 disk_device = argv[optind];
5834 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005835 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005836
5837 get_boot(fdisk);
5838
5839#ifdef CONFIG_FEATURE_OSF_LABEL
5840 if (osf_label) {
5841 /* OSF label, and no DOS label */
5842 printf(_("Detected an OSF/1 disklabel on %s, entering "
5843 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005844 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005845 bselect();
5846 osf_label = 0;
5847 /* If we return we may want to make an empty DOS label? */
5848 }
5849#endif
5850
5851 while (1) {
5852 putchar('\n');
5853 c = tolower(read_char(_("Command (m for help): ")));
5854 switch (c) {
5855 case 'a':
5856 if (dos_label)
5857 toggle_active(get_partition(1, partitions));
5858#ifdef CONFIG_FEATURE_SUN_LABEL
5859 else if (sun_label)
5860 toggle_sunflags(get_partition(1, partitions),
5861 0x01);
5862#endif
5863#ifdef CONFIG_FEATURE_SGI_LABEL
5864 else if (sgi_label)
5865 sgi_set_bootpartition(
5866 get_partition(1, partitions));
5867#endif
5868 else
5869 unknown_command(c);
5870 break;
5871 case 'b':
5872#ifdef CONFIG_FEATURE_SGI_LABEL
5873 if (sgi_label) {
5874 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005875 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005876 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005877 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005878 printf(_("Boot file unchanged\n"));
5879 else
5880 sgi_set_bootfile(line_ptr);
5881 } else
5882#endif
5883#ifdef CONFIG_FEATURE_OSF_LABEL
5884 bselect();
5885#endif
5886 break;
5887 case 'c':
5888 if (dos_label)
5889 toggle_dos_compatibility_flag();
5890#ifdef CONFIG_FEATURE_SUN_LABEL
5891 else if (sun_label)
5892 toggle_sunflags(get_partition(1, partitions),
5893 0x10);
5894#endif
5895#ifdef CONFIG_FEATURE_SGI_LABEL
5896 else if (sgi_label)
5897 sgi_set_swappartition(
5898 get_partition(1, partitions));
5899#endif
5900 else
5901 unknown_command(c);
5902 break;
5903 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005904 {
Eric Andersen040f4402003-07-30 08:40:37 +00005905 int j;
5906#ifdef CONFIG_FEATURE_SGI_LABEL
5907 /* If sgi_label then don't use get_existing_partition,
5908 let the user select a partition, since
5909 get_existing_partition() only works for Linux-like
5910 partition tables */
5911 if (!sgi_label) {
5912 j = get_existing_partition(1, partitions);
5913 } else {
5914 j = get_partition(1, partitions);
5915 }
5916#else
5917 j = get_existing_partition(1, partitions);
5918#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005919 if (j >= 0)
5920 delete_partition(j);
5921 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005922 break;
5923 case 'i':
5924#ifdef CONFIG_FEATURE_SGI_LABEL
5925 if (sgi_label)
5926 create_sgiinfo();
5927 else
5928#endif
5929 unknown_command(c);
5930 case 'l':
5931 list_types(get_sys_types());
5932 break;
5933 case 'm':
5934 menu();
5935 break;
5936 case 'n':
5937 new_partition();
5938 break;
5939 case 'o':
5940 create_doslabel();
5941 break;
5942 case 'p':
5943 list_table(0);
5944 break;
5945 case 'q':
5946 close(fd);
5947 printf("\n");
5948 return 0;
5949 case 's':
5950#ifdef CONFIG_FEATURE_SUN_LABEL
5951 create_sunlabel();
5952#endif
5953 break;
5954 case 't':
5955 change_sysid();
5956 break;
5957 case 'u':
5958 change_units();
5959 break;
5960 case 'v':
5961 verify();
5962 break;
5963 case 'w':
5964 write_table(); /* does not return */
5965 break;
5966#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5967 case 'x':
5968#ifdef CONFIG_FEATURE_SGI_LABEL
5969 if (sgi_label) {
5970 fprintf(stderr,
5971 _("\n\tSorry, no experts menu for SGI "
5972 "partition tables available.\n\n"));
5973 } else
5974#endif
5975
5976 xselect();
5977 break;
5978#endif
5979 default:
5980 unknown_command(c);
5981 menu();
5982 }
5983 }
5984 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005985#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005986}