blob: 2042951d9ecbc62cc3c412e279356f3a1ec55c1a [file] [log] [blame]
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
Mike Frysinger983e0ca2006-02-25 07:42:02 +00004 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005 *
Rob Landleyb73451d2006-02-24 16:29:00 +00006 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00007 */
8
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +00009/* Current changes have not compatibility with this version */
Eric Andersen99a75d12003-08-08 20:04:56 +000010#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000011
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000012
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000013#define PROC_PARTITIONS "/proc/partitions"
14
Eric Andersen256c4fd2004-05-19 09:00:00 +000015#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000016#include <sys/types.h>
17#include <sys/stat.h> /* stat */
18#include <ctype.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <errno.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <setjmp.h>
26#include <assert.h> /* assert */
27#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000028#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000029#include <sys/ioctl.h>
30#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000031#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000032
Eric Andersenacd244a2002-12-11 03:49:33 +000033#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
34
35/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000036#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000037
38#include <sys/utsname.h>
39
40#include "busybox.h"
41
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000042#define DKTYPENAMES
43
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000044#define BLKRRPART _IO(0x12,95) /* re-read partition table */
45#define BLKGETSIZE _IO(0x12,96) /* return device size */
46#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
47#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000048
49/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000050 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000051#undef _IOR
52#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000053#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000054
55/*
56 fdisk.h
57*/
58
59#define DEFAULT_SECTOR_SIZE 512
60#define MAX_SECTOR_SIZE 2048
61#define SECTOR_SIZE 512 /* still used in BSD code */
62#define MAXIMUM_PARTS 60
63
64#define ACTIVE_FLAG 0x80
65
66#define EXTENDED 0x05
67#define WIN98_EXTENDED 0x0f
68#define LINUX_PARTITION 0x81
69#define LINUX_SWAP 0x82
70#define LINUX_NATIVE 0x83
71#define LINUX_EXTENDED 0x85
72#define LINUX_LVM 0x8e
73#define LINUX_RAID 0xfd
74
75#define SUNOS_SWAP 3
76#define WHOLE_DISK 5
77
78#define IS_EXTENDED(i) \
79 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
80
81#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
82
83#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
84#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
85
Eric Andersen7495b0d2004-02-06 05:26:58 +000086#ifdef CONFIG_FEATURE_SUN_LABEL
87#define SCSI_IOCTL_GET_IDLUN 0x5382
88#endif
89
Eric Andersend3652bf2003-08-06 09:07:37 +000090
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000091/* including <linux/hdreg.h> also fails */
92struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000093 unsigned char heads;
94 unsigned char sectors;
95 unsigned short cylinders;
96 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000097};
98
99#define HDIO_GETGEO 0x0301 /* get device geometry */
100
101
102struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000103 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000104};
105
Rob Landleyb73451d2006-02-24 16:29:00 +0000106static uint sector_size = DEFAULT_SECTOR_SIZE;
107static uint user_set_sector_size;
108static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000109
110/*
111 * Raw disk label. For DOS-type partition tables the MBR,
112 * with descriptions of the primary partitions.
113 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000114#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000115static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000116#else
117# define MBRbuffer bb_common_bufsiz1
118#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000119
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000120#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000121static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000122#endif
123
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000124static uint heads, sectors, cylinders;
125static void update_units(void);
126
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000127
128/*
129 * return partition name - uses static storage unless buf is supplied
130 */
131static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000132partname(const char *dev, int pno, int lth)
133{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000134 static char buffer[80];
135 const char *p;
136 int w, wp;
137 int bufsiz;
138 char *bufp;
139
140 bufp = buffer;
141 bufsiz = sizeof(buffer);
142
143 w = strlen(dev);
144 p = "";
145
146 if (isdigit(dev[w-1]))
147 p = "p";
148
149 /* devfs kludge - note: fdisk partition names are not supposed
150 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000151 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000152 w -= 4;
153 p = "part";
154 }
155
156 wp = strlen(p);
157
158 if (lth) {
159 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
160 lth-wp-2, w, dev, p, pno);
161 } else {
162 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
163 }
164 return bufp;
165}
166
167struct partition {
168 unsigned char boot_ind; /* 0x80 - active */
169 unsigned char head; /* starting head */
170 unsigned char sector; /* starting sector */
171 unsigned char cyl; /* starting cylinder */
172 unsigned char sys_ind; /* What partition type */
173 unsigned char end_head; /* end head */
174 unsigned char end_sector; /* end sector */
175 unsigned char end_cyl; /* end cylinder */
176 unsigned char start4[4]; /* starting sector counting from 0 */
177 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000178} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000179
180enum failure {
181 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
182 unable_to_write
183};
184
Rob Landley5527b912006-02-25 03:46:10 +0000185enum label_type{
186 label_dos, label_sun, label_sgi, label_aix, label_osf
187};
188
Rob Landleyb73451d2006-02-24 16:29:00 +0000189enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000190
Rob Landley5527b912006-02-25 03:46:10 +0000191static enum label_type current_label_type;
192
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000193static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000194static int fd; /* the disk */
195static int partitions = 4; /* maximum partition + 1 */
196static uint display_in_cyl_units = 1;
197static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000198#ifdef CONFIG_FEATURE_FDISK_WRITABLE
199static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000200static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000201static void reread_partition_table(int leave);
202static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000203static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000204static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000205static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000206#endif
207static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000208static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000209static void get_geometry(void);
210static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000211
212#define PLURAL 0
213#define SINGULAR 1
214
215#define hex_val(c) ({ \
216 char _c = (c); \
217 isdigit(_c) ? _c - '0' : \
218 tolower(_c) + 10 - 'a'; \
219 })
220
221
222#define LINE_LENGTH 800
223#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
224 (n) * sizeof(struct partition)))
225#define sector(s) ((s) & 0x3f)
226#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
227
228#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
229 ((h) + heads * cylinder(s,c)))
230#define set_hsc(h,s,c,sector) { \
231 s = sector % sectors + 1; \
232 sector /= sectors; \
233 h = sector % heads; \
234 sector /= heads; \
235 c = sector & 0xff; \
236 s |= (sector >> 2) & 0xc0; \
237 }
238
239
Eric Andersend9261492004-06-28 23:50:31 +0000240static int32_t get_start_sect(const struct partition *p);
241static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000242
243/*
244 * per partition table entry data
245 *
246 * The four primary partitions have the same sectorbuffer (MBRbuffer)
247 * and have NULL ext_pointer.
248 * Each logical partition table entry has two pointers, one for the
249 * partition and one link to the next one.
250 */
251static struct pte {
252 struct partition *part_table; /* points into sectorbuffer */
253 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000254#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000255 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000256#endif
Eric Andersend9261492004-06-28 23:50:31 +0000257 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000258 char *sectorbuffer; /* disk sector contents */
259} ptes[MAXIMUM_PARTS];
260
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000261
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000262#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000263static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000264set_all_unchanged(void)
265{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000266 int i;
267
268 for (i = 0; i < MAXIMUM_PARTS; i++)
269 ptes[i].changed = 0;
270}
271
272static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000273set_changed(int i)
274{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000275 ptes[i].changed = 1;
276}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000277#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000278
279#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
280static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000281get_part_table(int i)
282{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000283 return ptes[i].part_table;
284}
285#endif
286
287static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000288str_units(int n)
289{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000290 if (n == 1)
291 return display_in_cyl_units ? _("cylinder") : _("sector");
292 else
293 return display_in_cyl_units ? _("cylinders") : _("sectors");
294}
295
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000296static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000297valid_part_table_flag(const char *mbuffer) {
298 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000299 return (b[510] == 0x55 && b[511] == 0xaa);
300}
301
302#ifdef CONFIG_FEATURE_FDISK_WRITABLE
303static char line_buffer[LINE_LENGTH];
304
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000305/* read line; return 0 or first char */
306static int
307read_line(void)
308{
309 static int got_eof = 0;
310
311 fflush (stdout); /* requested by niles@scyld.com */
312 line_ptr = line_buffer;
313 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
314 if (feof(stdin))
315 got_eof++; /* user typed ^D ? */
316 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000317 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
318 exit(1);
319 }
320 return 0;
321 }
322 while (*line_ptr && !isgraph(*line_ptr))
323 line_ptr++;
324 return *line_ptr;
325}
326
327static char
328read_char(const char *mesg)
329{
330 do {
331 fputs(mesg, stdout);
332 } while (!read_line());
333 return *line_ptr;
334}
335
336static char
337read_chars(const char *mesg)
338{
339 fputs(mesg, stdout);
340 if (!read_line()) {
341 *line_ptr = '\n';
342 line_ptr[1] = 0;
343 }
344 return *line_ptr;
345}
346
347static int
348read_hex(const struct systypes *sys)
349{
350 int hex;
351
Rob Landleyb73451d2006-02-24 16:29:00 +0000352 while (1) {
353 read_char(_("Hex code (type L to list codes): "));
354 if (*line_ptr == 'l' || *line_ptr == 'L')
355 list_types(sys);
356 else if (isxdigit (*line_ptr)) {
357 hex = 0;
358 do
359 hex = hex << 4 | hex_val(*line_ptr++);
360 while (isxdigit(*line_ptr));
361 return hex;
362 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000363 }
364}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000365#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000366
367#ifdef CONFIG_FEATURE_AIX_LABEL
368/*
369 * Copyright (C) Andreas Neuper, Sep 1998.
370 * This file may be redistributed under
371 * the terms of the GNU Public License.
372 */
373
374typedef struct {
375 unsigned int magic; /* expect AIX_LABEL_MAGIC */
376 unsigned int fillbytes1[124];
377 unsigned int physical_volume_id;
378 unsigned int fillbytes2[124];
379} aix_partition;
380
381#define AIX_LABEL_MAGIC 0xc9c2d4c1
382#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
383#define AIX_INFO_MAGIC 0x00072959
384#define AIX_INFO_MAGIC_SWAPPED 0x59290700
385
386#define aixlabel ((aix_partition *)MBRbuffer)
387
388
389/*
390 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000391 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
392 * Internationalization
393 *
394 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
395 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000396*/
397
Rob Landleyb73451d2006-02-24 16:29:00 +0000398static int aix_other_endian;
399static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000400
401/*
402 * only dealing with free blocks here
403 */
404
405static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000406aix_info(void)
407{
408 puts(
409 _("\n\tThere is a valid AIX label on this disk.\n"
410 "\tUnfortunately Linux cannot handle these\n"
411 "\tdisks at the moment. Nevertheless some\n"
412 "\tadvice:\n"
413 "\t1. fdisk will destroy its contents on write.\n"
414 "\t2. Be sure that this disk is NOT a still vital\n"
415 "\t part of a volume group. (Otherwise you may\n"
416 "\t erase the other disks as well, if unmirrored.)\n"
417 "\t3. Before deleting this physical volume be sure\n"
418 "\t to remove the disk logically from your AIX\n"
419 "\t machine. (Otherwise you become an AIXpert).")
420 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000421}
422
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000423static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000424check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000425{
Rob Landleyb73451d2006-02-24 16:29:00 +0000426 if (aixlabel->magic != AIX_LABEL_MAGIC &&
427 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000428 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000429 aix_other_endian = 0;
430 return 0;
431 }
432 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
433 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000434 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000435 partitions = 1016;
436 aix_volumes = 15;
437 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000438 /*aix_nolabel();*/ /* %% */
439 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000440 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000441}
442#endif /* AIX_LABEL */
443
444#ifdef CONFIG_FEATURE_OSF_LABEL
445/*
446 * Copyright (c) 1987, 1988 Regents of the University of California.
447 * All rights reserved.
448 *
449 * Redistribution and use in source and binary forms, with or without
450 * modification, are permitted provided that the following conditions
451 * are met:
452 * 1. Redistributions of source code must retain the above copyright
453 * notice, this list of conditions and the following disclaimer.
454 * 2. Redistributions in binary form must reproduce the above copyright
455 * notice, this list of conditions and the following disclaimer in the
456 * documentation and/or other materials provided with the distribution.
457 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000458 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000459 * This product includes software developed by the University of
460 * California, Berkeley and its contributors.
461 * 4. Neither the name of the University nor the names of its contributors
462 * may be used to endorse or promote products derived from this software
463 * without specific prior written permission.
464 *
465 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
466 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
467 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
468 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
469 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
470 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
471 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
472 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
473 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
474 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
475 * SUCH DAMAGE.
476 */
477
478
479#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000480#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000481#endif
482
483#ifndef BSD_MAXPARTITIONS
484#define BSD_MAXPARTITIONS 16
485#endif
486
487#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
488
489#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
490#define BSD_LABELSECTOR 1
491#define BSD_LABELOFFSET 0
492#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
493#define BSD_LABELSECTOR 0
494#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000495#elif defined (__s390__) || defined (__s390x__)
496#define BSD_LABELSECTOR 1
497#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000498#else
499#error unknown architecture
500#endif
501
502#define BSD_BBSIZE 8192 /* size of boot area, with label */
503#define BSD_SBSIZE 8192 /* max size of fs superblock */
504
505struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000506 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000507 int16_t d_type; /* drive type */
508 int16_t d_subtype; /* controller/d_type specific */
509 char d_typename[16]; /* type name, e.g. "eagle" */
510 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000511 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000512 uint32_t d_secsize; /* # of bytes per sector */
513 uint32_t d_nsectors; /* # of data sectors per track */
514 uint32_t d_ntracks; /* # of tracks per cylinder */
515 uint32_t d_ncylinders; /* # of data cylinders per unit */
516 uint32_t d_secpercyl; /* # of data sectors per cylinder */
517 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000518 /*
519 * Spares (bad sector replacements) below
520 * are not counted in d_nsectors or d_secpercyl.
521 * Spare sectors are assumed to be physical sectors
522 * which occupy space at the end of each track and/or cylinder.
523 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000524 uint16_t d_sparespertrack; /* # of spare sectors per track */
525 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000526 /*
527 * Alternate cylinders include maintenance, replacement,
528 * configuration description areas, etc.
529 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000530 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000531
532 /* hardware characteristics: */
533 /*
534 * d_interleave, d_trackskew and d_cylskew describe perturbations
535 * in the media format used to compensate for a slow controller.
536 * Interleave is physical sector interleave, set up by the formatter
537 * or controller when formatting. When interleaving is in use,
538 * logically adjacent sectors are not physically contiguous,
539 * but instead are separated by some number of sectors.
540 * It is specified as the ratio of physical sectors traversed
541 * per logical sector. Thus an interleave of 1:1 implies contiguous
542 * layout, while 2:1 implies that logical sector 0 is separated
543 * by one sector from logical sector 1.
544 * d_trackskew is the offset of sector 0 on track N
545 * relative to sector 0 on track N-1 on the same cylinder.
546 * Finally, d_cylskew is the offset of sector 0 on cylinder N
547 * relative to sector 0 on cylinder N-1.
548 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000549 uint16_t d_rpm; /* rotational speed */
550 uint16_t d_interleave; /* hardware sector interleave */
551 uint16_t d_trackskew; /* sector 0 skew, per track */
552 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
553 uint32_t d_headswitch; /* head switch time, usec */
554 uint32_t d_trkseek; /* track-to-track seek, usec */
555 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000556#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000557 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000558#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000559 uint32_t d_spare[NSPARE]; /* reserved for future use */
560 uint32_t d_magic2; /* the magic number (again) */
561 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000562 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000563 uint16_t d_npartitions; /* number of partitions in following */
564 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
565 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000566 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000567 uint32_t p_size; /* number of sectors in partition */
568 uint32_t p_offset; /* starting sector */
569 uint32_t p_fsize; /* filesystem basic fragment size */
570 uint8_t p_fstype; /* filesystem type, see below */
571 uint8_t p_frag; /* filesystem fragments per block */
572 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000573 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
574};
575
576/* d_type values: */
577#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
578#define BSD_DTYPE_MSCP 2 /* MSCP */
579#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
580#define BSD_DTYPE_SCSI 4 /* SCSI */
581#define BSD_DTYPE_ESDI 5 /* ESDI interface */
582#define BSD_DTYPE_ST506 6 /* ST506 etc. */
583#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
584#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
585#define BSD_DTYPE_FLOPPY 10 /* floppy */
586
587/* d_subtype values: */
588#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
589#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
590#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
591
592#ifdef DKTYPENAMES
593static const char * const xbsd_dktypenames[] = {
594 "unknown",
595 "SMD",
596 "MSCP",
597 "old DEC",
598 "SCSI",
599 "ESDI",
600 "ST506",
601 "HP-IB",
602 "HP-FL",
603 "type 9",
604 "floppy",
605 0
606};
607#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
608#endif
609
610/*
611 * Filesystem type and version.
612 * Used to interpret other filesystem-specific
613 * per-partition information.
614 */
615#define BSD_FS_UNUSED 0 /* unused */
616#define BSD_FS_SWAP 1 /* swap */
617#define BSD_FS_V6 2 /* Sixth Edition */
618#define BSD_FS_V7 3 /* Seventh Edition */
619#define BSD_FS_SYSV 4 /* System V */
620#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
621#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
622#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
623#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
624#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
625#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
626#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
627#define BSD_FS_ISOFS BSD_FS_ISO9660
628#define BSD_FS_BOOT 13 /* partition contains bootstrap */
629#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
630#define BSD_FS_HFS 15 /* Macintosh HFS */
631#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
632
633/* this is annoying, but it's also the way it is :-( */
634#ifdef __alpha__
635#define BSD_FS_EXT2 8 /* ext2 file system */
636#else
637#define BSD_FS_MSDOS 8 /* MS-DOS file system */
638#endif
639
640#ifdef DKTYPENAMES
641static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000642 { "\x00" "unused" }, /* BSD_FS_UNUSED */
643 { "\x01" "swap" }, /* BSD_FS_SWAP */
644 { "\x02" "Version 6" }, /* BSD_FS_V6 */
645 { "\x03" "Version 7" }, /* BSD_FS_V7 */
646 { "\x04" "System V" }, /* BSD_FS_SYSV */
647 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
648 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
649 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000650#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000651 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000652#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000653 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000654#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000655 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
656 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
657 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
658 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
659 { "\x0d" "boot" }, /* BSD_FS_BOOT */
660 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
661 { "\x0f" "HFS" }, /* BSD_FS_HFS */
662 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
663 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000664};
665#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
666
667#endif
668
669/*
670 * flags shared by various drives:
671 */
672#define BSD_D_REMOVABLE 0x01 /* removable media */
673#define BSD_D_ECC 0x02 /* supports ECC */
674#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
675#define BSD_D_RAMDISK 0x08 /* disk emulator */
676#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
677#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
678
679#endif /* OSF_LABEL */
680
681/*
682 * Copyright (C) Andreas Neuper, Sep 1998.
683 * This file may be modified and redistributed under
684 * the terms of the GNU Public License.
685 */
686
687struct device_parameter { /* 48 bytes */
688 unsigned char skew;
689 unsigned char gap1;
690 unsigned char gap2;
691 unsigned char sparecyl;
692 unsigned short pcylcount;
693 unsigned short head_vol0;
694 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
695 unsigned char cmd_tag_queue_depth;
696 unsigned char unused0;
697 unsigned short unused1;
698 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
699 unsigned short bytes;
700 unsigned short ilfact;
701 unsigned int flags; /* controller flags */
702 unsigned int datarate;
703 unsigned int retries_on_error;
704 unsigned int ms_per_word;
705 unsigned short xylogics_gap1;
706 unsigned short xylogics_syncdelay;
707 unsigned short xylogics_readdelay;
708 unsigned short xylogics_gap2;
709 unsigned short xylogics_readgate;
710 unsigned short xylogics_writecont;
711};
712
713#define SGI_VOLHDR 0x00
714/* 1 and 2 were used for drive types no longer supported by SGI */
715#define SGI_SWAP 0x03
716/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
717#define SGI_VOLUME 0x06
718#define SGI_EFS 0x07
719#define SGI_LVOL 0x08
720#define SGI_RLVOL 0x09
721#define SGI_XFS 0x0a
722#define SGI_XFSLOG 0x0b
723#define SGI_XLV 0x0c
724#define SGI_XVM 0x0d
725#define ENTIRE_DISK SGI_VOLUME
726/*
727 * controller flags
728 */
729#define SECTOR_SLIP 0x01
730#define SECTOR_FWD 0x02
731#define TRACK_FWD 0x04
732#define TRACK_MULTIVOL 0x08
733#define IGNORE_ERRORS 0x10
734#define RESEEK 0x20
735#define ENABLE_CMDTAGQ 0x40
736
737typedef struct {
738 unsigned int magic; /* expect SGI_LABEL_MAGIC */
739 unsigned short boot_part; /* active boot partition */
740 unsigned short swap_part; /* active swap partition */
741 unsigned char boot_file[16]; /* name of the bootfile */
742 struct device_parameter devparam; /* 1 * 48 bytes */
743 struct volume_directory { /* 15 * 16 bytes */
744 unsigned char vol_file_name[8]; /* a character array */
745 unsigned int vol_file_start; /* number of logical block */
746 unsigned int vol_file_size; /* number of bytes */
747 } directory[15];
748 struct sgi_partition { /* 16 * 12 bytes */
749 unsigned int num_sectors; /* number of blocks */
750 unsigned int start_sector; /* must be cylinder aligned */
751 unsigned int id;
752 } partitions[16];
753 unsigned int csum;
754 unsigned int fillbytes;
755} sgi_partition;
756
757typedef struct {
758 unsigned int magic; /* looks like a magic number */
759 unsigned int a2;
760 unsigned int a3;
761 unsigned int a4;
762 unsigned int b1;
763 unsigned short b2;
764 unsigned short b3;
765 unsigned int c[16];
766 unsigned short d[3];
767 unsigned char scsi_string[50];
768 unsigned char serial[137];
769 unsigned short check1816;
770 unsigned char installer[225];
771} sgiinfo;
772
773#define SGI_LABEL_MAGIC 0x0be5a941
774#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
775#define SGI_INFO_MAGIC 0x00072959
776#define SGI_INFO_MAGIC_SWAPPED 0x59290700
777#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000778 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000779#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000780 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000781
782#define sgilabel ((sgi_partition *)MBRbuffer)
783#define sgiparam (sgilabel->devparam)
784
785typedef struct {
786 unsigned char info[128]; /* Informative text string */
787 unsigned char spare0[14];
788 struct sun_info {
789 unsigned char spare1;
790 unsigned char id;
791 unsigned char spare2;
792 unsigned char flags;
793 } infos[8];
794 unsigned char spare1[246]; /* Boot information etc. */
795 unsigned short rspeed; /* Disk rotational speed */
796 unsigned short pcylcount; /* Physical cylinder count */
797 unsigned short sparecyl; /* extra sects per cylinder */
798 unsigned char spare2[4]; /* More magic... */
799 unsigned short ilfact; /* Interleave factor */
800 unsigned short ncyl; /* Data cylinder count */
801 unsigned short nacyl; /* Alt. cylinder count */
802 unsigned short ntrks; /* Tracks per cylinder */
803 unsigned short nsect; /* Sectors per track */
804 unsigned char spare3[4]; /* Even more magic... */
805 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000806 uint32_t start_cylinder;
807 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000808 } partitions[8];
809 unsigned short magic; /* Magic number */
810 unsigned short csum; /* Label xor'd checksum */
811} sun_partition;
812
Eric Andersen040f4402003-07-30 08:40:37 +0000813
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000814#define SUN_LABEL_MAGIC 0xDABE
815#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
816#define sunlabel ((sun_partition *)MBRbuffer)
817#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000818 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000819#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000820 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000821
Eric Andersend3652bf2003-08-06 09:07:37 +0000822
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000823#ifdef CONFIG_FEATURE_OSF_LABEL
824/*
825 Changes:
826 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
827
828 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
829 support for OSF/1 disklabels on Alpha.
830 Also fixed unaligned accesses in alpha_bootblock_checksum()
831*/
832
833#define FREEBSD_PARTITION 0xa5
834#define NETBSD_PARTITION 0xa9
835
Rob Landleyb73451d2006-02-24 16:29:00 +0000836static void xbsd_delete_part(void);
837static void xbsd_new_part(void);
838static void xbsd_write_disklabel(void);
839static int xbsd_create_disklabel(void);
840static void xbsd_edit_disklabel(void);
841static void xbsd_write_bootstrap(void);
842static void xbsd_change_fstype(void);
843static int xbsd_get_part_index(int max);
844static int xbsd_check_new_partition(int *i);
845static void xbsd_list_types(void);
846static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
847static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
848static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
849static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000850
851#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000852static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000853#endif
854
855#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000856static int xbsd_translate_fstype(int linux_type);
857static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000858static struct partition *xbsd_part;
859static int xbsd_part_index;
860#endif
861
862#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000863/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000864static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000865#else
866static char disklabelbuffer[BSD_BBSIZE];
867#endif
868
869static struct xbsd_disklabel xbsd_dlabel;
870
871#define bsd_cround(n) \
872 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
873
874/*
875 * Test whether the whole disk has BSD disk label magic.
876 *
877 * Note: often reformatting with DOS-type label leaves the BSD magic,
878 * so this does not mean that there is a BSD disk label.
879 */
880static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000881check_osf_label(void)
882{
883 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000884 return 0;
885 return 1;
886}
887
888static void xbsd_print_disklabel(int);
889
890static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000891btrydev(const char * dev)
892{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000893 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
894 return -1;
895 printf(_("\nBSD label for device: %s\n"), dev);
896 xbsd_print_disklabel (0);
897 return 0;
898}
899
900static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000901bmenu(void)
902{
903 puts (_("Command action"));
904 puts (_("\td\tdelete a BSD partition"));
905 puts (_("\te\tedit drive data"));
906 puts (_("\ti\tinstall bootstrap"));
907 puts (_("\tl\tlist known filesystem types"));
908 puts (_("\tm\tprint this menu"));
909 puts (_("\tn\tadd a new BSD partition"));
910 puts (_("\tp\tprint BSD partition table"));
911 puts (_("\tq\tquit without saving changes"));
912 puts (_("\tr\treturn to main menu"));
913 puts (_("\ts\tshow complete disklabel"));
914 puts (_("\tt\tchange a partition's filesystem id"));
915 puts (_("\tu\tchange units (cylinders/sectors)"));
916 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000917#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000918 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000919#endif
920}
921
922#if !defined (__alpha__)
923static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000924hidden(int type)
925{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000926 return type ^ 0x10;
927}
928
929static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000930is_bsd_partition_type(int type)
931{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000932 return (type == FREEBSD_PARTITION ||
933 type == hidden(FREEBSD_PARTITION) ||
934 type == NETBSD_PARTITION ||
935 type == hidden(NETBSD_PARTITION));
936}
937#endif
938
939static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000940bselect(void)
941{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000942#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000943 int t, ss;
944 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000945
Rob Landleyb73451d2006-02-24 16:29:00 +0000946 for (t = 0; t < 4; t++) {
947 p = get_part_table(t);
948 if (p && is_bsd_partition_type(p->sys_ind)) {
949 xbsd_part = p;
950 xbsd_part_index = t;
951 ss = get_start_sect(xbsd_part);
952 if (ss == 0) {
953 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
954 partname(disk_device, t+1, 0));
955 return;
956 }
957 printf(_("Reading disklabel of %s at sector %d.\n"),
958 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
959 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
960 if (xbsd_create_disklabel() == 0)
961 return;
962 break;
963 }
964 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000965
Rob Landleyb73451d2006-02-24 16:29:00 +0000966 if (t == 4) {
967 printf(_("There is no *BSD partition on %s.\n"), disk_device);
968 return;
969 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000970
971#elif defined (__alpha__)
972
Rob Landleyb73451d2006-02-24 16:29:00 +0000973 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
974 if (xbsd_create_disklabel() == 0)
975 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000976
977#endif
978
Rob Landleyb73451d2006-02-24 16:29:00 +0000979 while (1) {
980 putchar('\n');
981 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
982 case 'd':
983 xbsd_delete_part();
984 break;
985 case 'e':
986 xbsd_edit_disklabel();
987 break;
988 case 'i':
989 xbsd_write_bootstrap();
990 break;
991 case 'l':
992 xbsd_list_types();
993 break;
994 case 'n':
995 xbsd_new_part();
996 break;
997 case 'p':
998 xbsd_print_disklabel(0);
999 break;
1000 case 'q':
1001 close(fd);
1002 exit(EXIT_SUCCESS);
1003 case 'r':
1004 return;
1005 case 's':
1006 xbsd_print_disklabel(1);
1007 break;
1008 case 't':
1009 xbsd_change_fstype();
1010 break;
1011 case 'u':
1012 change_units();
1013 break;
1014 case 'w':
1015 xbsd_write_disklabel();
1016 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001017#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001018 case 'x':
1019 xbsd_link_part();
1020 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001021#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001022 default:
1023 bmenu();
1024 break;
1025 }
1026 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001027}
1028
1029static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001030xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001031{
Rob Landleyb73451d2006-02-24 16:29:00 +00001032 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001033
Rob Landleyb73451d2006-02-24 16:29:00 +00001034 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1035 xbsd_dlabel.d_partitions[i].p_size = 0;
1036 xbsd_dlabel.d_partitions[i].p_offset = 0;
1037 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1038 if (xbsd_dlabel.d_npartitions == i + 1)
1039 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1040 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001041}
1042
1043static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001044xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001045{
Rob Landleyb73451d2006-02-24 16:29:00 +00001046 off_t begin, end;
1047 char mesg[256];
1048 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001049
Rob Landleyb73451d2006-02-24 16:29:00 +00001050 if (!xbsd_check_new_partition(&i))
1051 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001052
1053#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001054 begin = get_start_sect(xbsd_part);
1055 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001056#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001057 begin = 0;
1058 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001059#endif
1060
Rob Landleyb73451d2006-02-24 16:29:00 +00001061 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1062 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1063 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001064
Rob Landleyb73451d2006-02-24 16:29:00 +00001065 if (display_in_cyl_units)
1066 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001067
Rob Landleyb73451d2006-02-24 16:29:00 +00001068 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1069 str_units(SINGULAR));
1070 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1071 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001072
Rob Landleyb73451d2006-02-24 16:29:00 +00001073 if (display_in_cyl_units)
1074 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001075
Rob Landleyb73451d2006-02-24 16:29:00 +00001076 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1077 xbsd_dlabel.d_partitions[i].p_offset = begin;
1078 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001079}
1080
1081static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001082xbsd_print_disklabel(int show_all)
1083{
1084 struct xbsd_disklabel *lp = &xbsd_dlabel;
1085 struct xbsd_partition *pp;
1086 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001087
Rob Landleyb73451d2006-02-24 16:29:00 +00001088 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001089#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001090 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001091#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001092 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001093#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001094 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1095 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1096 else
1097 printf(_("type: %d\n"), lp->d_type);
1098 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1099 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1100 printf(_("flags:"));
1101 if (lp->d_flags & BSD_D_REMOVABLE)
1102 printf(_(" removable"));
1103 if (lp->d_flags & BSD_D_ECC)
1104 printf(_(" ecc"));
1105 if (lp->d_flags & BSD_D_BADSECT)
1106 printf(_(" badsect"));
1107 printf("\n");
1108 /* On various machines the fields of *lp are short/int/long */
1109 /* In order to avoid problems, we cast them all to long. */
1110 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1111 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1112 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1113 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1114 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1115 printf(_("rpm: %d\n"), lp->d_rpm);
1116 printf(_("interleave: %d\n"), lp->d_interleave);
1117 printf(_("trackskew: %d\n"), lp->d_trackskew);
1118 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1119 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1120 (long) lp->d_headswitch);
1121 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1122 (long) lp->d_trkseek);
1123 printf(_("drivedata: "));
1124 for (i = NDDATA - 1; i >= 0; i--)
1125 if (lp->d_drivedata[i])
1126 break;
1127 if (i < 0)
1128 i = 0;
1129 for (j = 0; j <= i; j++)
1130 printf("%ld ", (long) lp->d_drivedata[j]);
1131 }
1132 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1133 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1134 pp = lp->d_partitions;
1135 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1136 if (pp->p_size) {
1137 if (display_in_cyl_units && lp->d_secpercyl) {
1138 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1139 'a' + i,
1140 (long) pp->p_offset / lp->d_secpercyl + 1,
1141 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1142 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1143 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1144 (long) pp->p_size / lp->d_secpercyl,
1145 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1146 );
1147 } else {
1148 printf(" %c: %8ld %8ld %8ld ",
1149 'a' + i,
1150 (long) pp->p_offset,
1151 (long) pp->p_offset + pp->p_size - 1,
1152 (long) pp->p_size
1153 );
1154 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001155
Rob Landleyb73451d2006-02-24 16:29:00 +00001156 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1157 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1158 else
1159 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001160
Rob Landleyb73451d2006-02-24 16:29:00 +00001161 switch (pp->p_fstype) {
1162 case BSD_FS_UNUSED:
1163 printf(" %5ld %5ld %5.5s ",
1164 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1165 break;
1166 case BSD_FS_BSDFFS:
1167 printf(" %5ld %5ld %5d ",
1168 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1169 break;
1170 default:
1171 printf("%22.22s", "");
1172 break;
1173 }
1174 printf("\n");
1175 }
1176 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001177}
1178
1179static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001180xbsd_write_disklabel(void)
1181{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001182#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001183 printf(_("Writing disklabel to %s.\n"), disk_device);
1184 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001185#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001186 printf(_("Writing disklabel to %s.\n"),
1187 partname(disk_device, xbsd_part_index + 1, 0));
1188 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001189#endif
1190 reread_partition_table(0); /* no exit yet */
1191}
1192
1193static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001194xbsd_create_disklabel(void)
1195{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001196 char c;
1197
1198#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001199 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001200#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001201 fprintf(stderr, _("%s contains no disklabel.\n"),
1202 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001203#endif
1204
1205 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001206 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001207 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001208 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001209#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001210 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001211 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001212#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001213 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001214#endif
1215 ) == 1) {
1216 xbsd_print_disklabel (1);
1217 return 1;
1218 } else
1219 return 0;
1220 } else if (c == 'n')
1221 return 0;
1222 }
1223}
1224
1225static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001226edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001227{
Rob Landleyb73451d2006-02-24 16:29:00 +00001228 do {
1229 fputs(mesg, stdout);
1230 printf(" (%d): ", def);
1231 if (!read_line())
1232 return def;
1233 }
1234 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1235 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001236}
1237
1238static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001239xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001240{
Rob Landleyb73451d2006-02-24 16:29:00 +00001241 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001242
Rob Landleyb73451d2006-02-24 16:29:00 +00001243 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001244
1245#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001246 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1247 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1248 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1249 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001250#endif
1251
Rob Landleyb73451d2006-02-24 16:29:00 +00001252 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1253 while (1) {
1254 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1255 _("sectors/cylinder"));
1256 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1257 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001258
Rob Landleyb73451d2006-02-24 16:29:00 +00001259 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1260 }
1261 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1262 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1263 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1264 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1265 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1266 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001267
Rob Landleyb73451d2006-02-24 16:29:00 +00001268 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001269}
1270
1271static int
1272xbsd_get_bootstrap (char *path, void *ptr, int size)
1273{
Rob Landleyb73451d2006-02-24 16:29:00 +00001274 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001275
Rob Landleyb73451d2006-02-24 16:29:00 +00001276 if ((fdb = open (path, O_RDONLY)) < 0) {
1277 perror(path);
1278 return 0;
1279 }
1280 if (read(fdb, ptr, size) < 0) {
1281 perror(path);
1282 close(fdb);
1283 return 0;
1284 }
1285 printf(" ... %s\n", path);
1286 close(fdb);
1287 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001288}
1289
1290static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001291sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001292{
Rob Landleyb73451d2006-02-24 16:29:00 +00001293 printf(_("\nSyncing disks.\n"));
1294 sync();
1295 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001296}
1297
1298static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001299xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001300{
Rob Landleyb73451d2006-02-24 16:29:00 +00001301 char *bootdir = BSD_LINUX_BOOTDIR;
1302 char path[MAXPATHLEN];
1303 char *dkbasename;
1304 struct xbsd_disklabel dl;
1305 char *d, *p, *e;
1306 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001307
Rob Landleyb73451d2006-02-24 16:29:00 +00001308 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1309 dkbasename = "sd";
1310 else
1311 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001312
Rob Landleyb73451d2006-02-24 16:29:00 +00001313 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1314 dkbasename, dkbasename, dkbasename);
1315 if (read_line()) {
1316 line_ptr[strlen(line_ptr)-1] = '\0';
1317 dkbasename = line_ptr;
1318 }
1319 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1320 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1321 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001322
Rob Landleyb73451d2006-02-24 16:29:00 +00001323/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1324 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
Mike Frysinger1a540302006-04-16 05:58:21 +00001325 memmove(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001326
Rob Landleyb73451d2006-02-24 16:29:00 +00001327/* The disklabel will be overwritten by 0's from bootxx anyway */
1328 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001329
Rob Landleyb73451d2006-02-24 16:29:00 +00001330 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1331 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001332 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001333 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001334
Rob Landleyb73451d2006-02-24 16:29:00 +00001335 e = d + sizeof(struct xbsd_disklabel);
1336 for (p = d; p < e; p++)
1337 if (*p) {
1338 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1339 exit(EXIT_FAILURE);
1340 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001341
Mike Frysinger1a540302006-04-16 05:58:21 +00001342 memmove(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001343
1344#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001345 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001346#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001347 sector = 0;
1348 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001349#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001350 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001351#endif
1352
Rob Landleyb73451d2006-02-24 16:29:00 +00001353 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1354 fdisk_fatal(unable_to_seek);
1355 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1356 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001357
1358#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001359 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001360#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001361 printf(_("Bootstrap installed on %s.\n"),
1362 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001363#endif
1364
Rob Landleyb73451d2006-02-24 16:29:00 +00001365 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001366}
1367
1368static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001369xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001370{
Rob Landleyb73451d2006-02-24 16:29:00 +00001371 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001372
Rob Landleyb73451d2006-02-24 16:29:00 +00001373 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1374 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001375}
1376
1377static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001378xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001379{
Rob Landleyb73451d2006-02-24 16:29:00 +00001380 char prompt[256];
1381 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001382
Rob Landleyb73451d2006-02-24 16:29:00 +00001383 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1384 do
1385 l = tolower(read_char(prompt));
1386 while (l < 'a' || l > 'a' + max - 1);
1387 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001388}
1389
1390static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001391xbsd_check_new_partition(int *i)
1392{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001393 /* room for more? various BSD flavours have different maxima */
1394 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1395 int t;
1396
1397 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1398 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1399 break;
1400
1401 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001402 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001403 "has been created\n"));
1404 return 0;
1405 }
1406 }
1407
1408 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1409
1410 if (*i >= xbsd_dlabel.d_npartitions)
1411 xbsd_dlabel.d_npartitions = (*i) + 1;
1412
1413 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001414 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001415 return 0;
1416 }
1417
1418 return 1;
1419}
1420
1421static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001422xbsd_list_types(void)
1423{
1424 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001425}
1426
1427static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001428xbsd_dkcksum(struct xbsd_disklabel *lp)
1429{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001430 u_short *start, *end;
1431 u_short sum = 0;
1432
1433 start = (u_short *) lp;
1434 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1435 while (start < end)
1436 sum ^= *start++;
1437 return sum;
1438}
1439
1440static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001441xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1442{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001443 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001444
Rob Landleyb73451d2006-02-24 16:29:00 +00001445 get_geometry();
1446 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001447
Rob Landleyb73451d2006-02-24 16:29:00 +00001448 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001449
Rob Landleyb73451d2006-02-24 16:29:00 +00001450 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1451 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001452 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001453 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001454
1455#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001456 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001457#endif
1458
1459#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001460 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001461#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001462 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001463#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001464 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1465 d->d_nsectors = sectors; /* sectors/track */
1466 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1467 d->d_ncylinders = cylinders;
1468 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1469 if (d->d_secpercyl == 0)
1470 d->d_secpercyl = 1; /* avoid segfaults */
1471 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001472
Rob Landleyb73451d2006-02-24 16:29:00 +00001473 d->d_rpm = 3600;
1474 d->d_interleave = 1;
1475 d->d_trackskew = 0;
1476 d->d_cylskew = 0;
1477 d->d_headswitch = 0;
1478 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001479
Rob Landleyb73451d2006-02-24 16:29:00 +00001480 d->d_magic2 = BSD_DISKMAGIC;
1481 d->d_bbsize = BSD_BBSIZE;
1482 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001483
1484#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001485 d->d_npartitions = 4;
1486 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001487 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001488 pp->p_offset = get_start_sect(p);
1489 pp->p_size = get_nr_sects(p);
1490 pp->p_fstype = BSD_FS_UNUSED;
1491 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001492 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001493 pp->p_offset = 0;
1494 pp->p_size = d->d_secperunit;
1495 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001496#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001497 d->d_npartitions = 3;
1498 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001499 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001500 pp->p_offset = 0;
1501 pp->p_size = d->d_secperunit;
1502 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001503#endif
1504
1505 return 1;
1506}
1507
1508/*
1509 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1510 * If it has the right magic, return 1.
1511 */
1512static int
1513xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1514{
1515 int t, sector;
1516
1517 /* p is used only to get the starting sector */
1518#if !defined (__alpha__)
1519 sector = (p ? get_start_sect(p) : 0);
1520#elif defined (__alpha__)
1521 sector = 0;
1522#endif
1523
Rob Landleyb73451d2006-02-24 16:29:00 +00001524 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1525 fdisk_fatal(unable_to_seek);
1526 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1527 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001528
Mike Frysinger1a540302006-04-16 05:58:21 +00001529 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1530 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001531
Rob Landleyb73451d2006-02-24 16:29:00 +00001532 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001533 return 0;
1534
Rob Landleyb73451d2006-02-24 16:29:00 +00001535 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1536 d->d_partitions[t].p_size = 0;
1537 d->d_partitions[t].p_offset = 0;
1538 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001539 }
1540
Rob Landleyb73451d2006-02-24 16:29:00 +00001541 if (d->d_npartitions > BSD_MAXPARTITIONS)
1542 fprintf(stderr, _("Warning: too many partitions "
1543 "(%d, maximum is %d).\n"),
1544 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001545 return 1;
1546}
1547
1548static int
1549xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1550{
Rob Landleyb73451d2006-02-24 16:29:00 +00001551 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001552
1553#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001554 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001555#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001556 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001557#endif
1558
Rob Landleyb73451d2006-02-24 16:29:00 +00001559 d->d_checksum = 0;
1560 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001561
Rob Landleyb73451d2006-02-24 16:29:00 +00001562 /* This is necessary if we want to write the bootstrap later,
1563 otherwise we'd write the old disklabel with the bootstrap.
1564 */
Mike Frysinger1a540302006-04-16 05:58:21 +00001565 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1566 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001567
1568#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001569 alpha_bootblock_checksum (disklabelbuffer);
1570 if (lseek(fd, 0, SEEK_SET) == -1)
1571 fdisk_fatal(unable_to_seek);
1572 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1573 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001574#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001575 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1576 fdisk_fatal(unable_to_seek);
1577 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1578 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001579#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001580 sync_disks();
1581 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001582}
1583
1584
1585#if !defined (__alpha__)
1586static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001587xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001588{
Rob Landleyb73451d2006-02-24 16:29:00 +00001589 switch (linux_type) {
1590 case 0x01: /* DOS 12-bit FAT */
1591 case 0x04: /* DOS 16-bit <32M */
1592 case 0x06: /* DOS 16-bit >=32M */
1593 case 0xe1: /* DOS access */
1594 case 0xe3: /* DOS R/O */
1595 case 0xf2: /* DOS secondary */
1596 return BSD_FS_MSDOS;
1597 case 0x07: /* OS/2 HPFS */
1598 return BSD_FS_HPFS;
1599 default:
1600 return BSD_FS_OTHER;
1601 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001602}
1603
1604static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001605xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001606{
Rob Landleyb73451d2006-02-24 16:29:00 +00001607 int k, i;
1608 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001609
Rob Landleyb73451d2006-02-24 16:29:00 +00001610 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001611
Rob Landleyb73451d2006-02-24 16:29:00 +00001612 if (!xbsd_check_new_partition(&i))
1613 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001614
Rob Landleyb73451d2006-02-24 16:29:00 +00001615 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001616
Rob Landleyb73451d2006-02-24 16:29:00 +00001617 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1618 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1619 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001620}
1621#endif
1622
1623#if defined (__alpha__)
1624
1625#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001626typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001627#endif
1628
1629static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001630alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001631{
Rob Landleyb73451d2006-02-24 16:29:00 +00001632 uint64_t *dp, sum;
1633 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001634
Rob Landleyb73451d2006-02-24 16:29:00 +00001635 dp = (uint64_t *)boot;
1636 sum = 0;
1637 for (i = 0; i < 63; i++)
1638 sum += dp[i];
1639 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001640}
1641#endif /* __alpha__ */
1642
1643#endif /* OSF_LABEL */
1644
1645#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1646static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001647__swap16(unsigned short x)
1648{
Eric Andersenacd244a2002-12-11 03:49:33 +00001649 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001650}
1651
Eric Andersenacd244a2002-12-11 03:49:33 +00001652static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001653__swap32(uint32_t x)
1654{
1655 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001656 ((x & 0xFF00) << 8) |
1657 ((x & 0xFF0000) >> 8) |
1658 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001659}
1660#endif
1661
1662#ifdef CONFIG_FEATURE_SGI_LABEL
1663/*
1664 *
1665 * fdisksgilabel.c
1666 *
1667 * Copyright (C) Andreas Neuper, Sep 1998.
1668 * This file may be modified and redistributed under
1669 * the terms of the GNU Public License.
1670 *
1671 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1672 * Internationalization
1673 */
1674
1675
Rob Landleyb73451d2006-02-24 16:29:00 +00001676static int sgi_other_endian;
1677static int debug;
1678static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001679
1680/*
1681 * only dealing with free blocks here
1682 */
1683
Rob Landleyb73451d2006-02-24 16:29:00 +00001684typedef struct {
1685 unsigned int first;
1686 unsigned int last;
1687} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001688static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1689
1690static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001691setfreelist(int i, unsigned int f, unsigned int l)
1692{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001693 freelist[i].first = f;
1694 freelist[i].last = l;
1695}
1696
1697static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001698add2freelist(unsigned int f, unsigned int l)
1699{
1700 int i;
1701 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001702 if (freelist[i].last == 0)
1703 break;
1704 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001705}
1706
1707static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001708clearfreelist(void)
1709{
Eric Andersen040f4402003-07-30 08:40:37 +00001710 int i;
1711
1712 for (i = 0; i < 17 ; i++)
1713 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001714}
1715
Eric Andersen040f4402003-07-30 08:40:37 +00001716static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001717isinfreelist(unsigned int b)
1718{
Eric Andersen040f4402003-07-30 08:40:37 +00001719 int i;
1720
1721 for (i = 0; i < 17 ; i++)
1722 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001723 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001724 return 0;
1725}
1726 /* return last vacant block of this stride (never 0). */
1727 /* the '>=' is not quite correct, but simplifies the code */
1728/*
1729 * end of free blocks section
1730 */
1731
1732static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001733/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1734/* 0x01 */ { "\x01" "SGI trkrepl" },
1735/* 0x02 */ { "\x02" "SGI secrepl" },
1736/* SGI_SWAP */ { "\x03" "SGI raw" },
1737/* 0x04 */ { "\x04" "SGI bsd" },
1738/* 0x05 */ { "\x05" "SGI sysv" },
1739/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1740/* SGI_EFS */ { "\x07" "SGI efs" },
1741/* 0x08 */ { "\x08" "SGI lvol" },
1742/* 0x09 */ { "\x09" "SGI rlvol" },
1743/* SGI_XFS */ { "\x0a" "SGI xfs" },
1744/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1745/* SGI_XLV */ { "\x0c" "SGI xlv" },
1746/* SGI_XVM */ { "\x0d" "SGI xvm" },
1747/* LINUX_SWAP */ { "\x82" "Linux swap" },
1748/* LINUX_NATIVE */ { "\x83" "Linux native" },
1749/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1750/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1751 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001752};
1753
1754
1755static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001756sgi_get_nsect(void)
1757{
1758 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001759}
1760
1761static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001762sgi_get_ntrks(void)
1763{
1764 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001765}
1766
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001767static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001768two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1769{
1770 int i = 0;
1771 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001772
Rob Landleyb73451d2006-02-24 16:29:00 +00001773 size /= sizeof(unsigned int);
1774 for (i = 0; i < size; i++)
1775 sum -= SGI_SSWAP32(base[i]);
1776 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001777}
1778
1779static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001780check_sgi_label(void)
1781{
1782 if (sizeof(sgilabel) > 512) {
1783 fprintf(stderr,
1784 _("According to MIPS Computer Systems, Inc the "
1785 "Label must not contain more than 512 bytes\n"));
1786 exit(1);
1787 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001788
Rob Landleyb73451d2006-02-24 16:29:00 +00001789 if (sgilabel->magic != SGI_LABEL_MAGIC
1790 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001791 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001792 return 0;
1793 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001794
Rob Landleyb73451d2006-02-24 16:29:00 +00001795 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1796 /*
1797 * test for correct checksum
1798 */
1799 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1800 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001801 fprintf(stderr,
1802 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001803 }
1804 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001805 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001806 partitions = 16;
1807 sgi_volumes = 15;
1808 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001809}
1810
Eric Andersen040f4402003-07-30 08:40:37 +00001811static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001812sgi_get_start_sector(int i)
1813{
1814 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001815}
1816
Eric Andersen040f4402003-07-30 08:40:37 +00001817static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001818sgi_get_num_sectors(int i)
1819{
1820 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001821}
1822
1823static int
Eric Andersen040f4402003-07-30 08:40:37 +00001824sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001825{
Rob Landleyb73451d2006-02-24 16:29:00 +00001826 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001827}
1828
1829static int
1830sgi_get_bootpartition(void)
1831{
Rob Landleyb73451d2006-02-24 16:29:00 +00001832 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001833}
1834
1835static int
1836sgi_get_swappartition(void)
1837{
Rob Landleyb73451d2006-02-24 16:29:00 +00001838 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001839}
1840
1841static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001842sgi_list_table(int xtra)
1843{
1844 int i, w, wd;
1845 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001846
Rob Landleyb73451d2006-02-24 16:29:00 +00001847 if(xtra) {
1848 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1849 "%d cylinders, %d physical cylinders\n"
1850 "%d extra sects/cyl, interleave %d:1\n"
1851 "%s\n"
1852 "Units = %s of %d * 512 bytes\n\n"),
1853 disk_device, heads, sectors, cylinders,
1854 SGI_SSWAP16(sgiparam.pcylcount),
1855 SGI_SSWAP16(sgiparam.sparecyl),
1856 SGI_SSWAP16(sgiparam.ilfact),
1857 (char *)sgilabel,
1858 str_units(PLURAL), units_per_sector);
1859 } else {
1860 printf( _("\nDisk %s (SGI disk label): "
1861 "%d heads, %d sectors, %d cylinders\n"
1862 "Units = %s of %d * 512 bytes\n\n"),
1863 disk_device, heads, sectors, cylinders,
1864 str_units(PLURAL), units_per_sector );
1865 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001866
Rob Landleyb73451d2006-02-24 16:29:00 +00001867 w = strlen(disk_device);
1868 wd = strlen(_("Device"));
1869 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001870 w = wd;
1871
Rob Landleyb73451d2006-02-24 16:29:00 +00001872 printf(_("----- partitions -----\n"
1873 "Pt# %*s Info Start End Sectors Id System\n"),
1874 w + 2, _("Device"));
1875 for (i = 0 ; i < partitions; i++) {
1876 if( sgi_get_num_sectors(i) || debug ) {
1877 uint32_t start = sgi_get_start_sector(i);
1878 uint32_t len = sgi_get_num_sectors(i);
1879 kpi++; /* only count nonempty partitions */
1880 printf(
1881 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1882/* fdisk part number */ i+1,
1883/* device */ partname(disk_device, kpi, w+3),
1884/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1885/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1886/* start */ (long) scround(start),
1887/* end */ (long) scround(start+len)-1,
1888/* no odd flag on end */(long) len,
1889/* type id */ sgi_get_sysid(i),
1890/* type name */ partition_type(sgi_get_sysid(i)));
1891 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001892 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001893 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1894 "----- Directory Entries -----\n"),
1895 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001896 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001897 if (sgilabel->directory[i].vol_file_size) {
1898 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1899 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1900 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001901
Rob Landleyb73451d2006-02-24 16:29:00 +00001902 printf(_("%2d: %-10s sector%5u size%8u\n"),
1903 i, (char*)name, (unsigned int) start, (unsigned int) len);
1904 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001905 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001906}
1907
1908static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001909sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001910{
Rob Landleyb73451d2006-02-24 16:29:00 +00001911 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001912}
1913
Eric Andersen040f4402003-07-30 08:40:37 +00001914static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001915sgi_get_lastblock(void)
1916{
1917 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001918}
1919
1920static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001921sgi_set_swappartition(int i)
1922{
1923 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001924}
1925
1926static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001927sgi_check_bootfile(const char* aFile)
1928{
1929 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1930 printf(_("\nInvalid Bootfile!\n"
1931 "\tThe bootfile must be an absolute non-zero pathname,\n"
1932 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1933 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001934 } else {
1935 if (strlen(aFile) > 16) {
1936 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001937 "16 bytes maximum.\n"));
1938 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001939 } else {
1940 if (aFile[0] != '/') {
1941 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001942 "fully qualified pathname.\n"));
1943 return 0;
1944 }
Eric Andersen040f4402003-07-30 08:40:37 +00001945 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001946 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001947 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001948 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1949 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001950 /* filename is correct and did change */
1951 return 1;
1952 }
1953 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001954}
1955
1956static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001957sgi_get_bootfile(void)
1958{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001959 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001960}
1961
1962static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001963sgi_set_bootfile(const char* aFile)
1964{
1965 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001966
Rob Landleyb73451d2006-02-24 16:29:00 +00001967 if (sgi_check_bootfile(aFile)) {
1968 while (i < 16) {
1969 if ((aFile[i] != '\n') /* in principle caught again by next line */
1970 && (strlen(aFile) > i))
1971 sgilabel->boot_file[i] = aFile[i];
1972 else
1973 sgilabel->boot_file[i] = 0;
1974 i++;
1975 }
1976 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001977 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001978}
1979
1980static void
1981create_sgiinfo(void)
1982{
Rob Landleyb73451d2006-02-24 16:29:00 +00001983 /* I keep SGI's habit to write the sgilabel to the second block */
1984 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1985 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1986 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001987}
1988
Eric Andersen040f4402003-07-30 08:40:37 +00001989static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001990
1991static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001992sgi_write_table(void)
1993{
1994 sgilabel->csum = 0;
1995 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1996 (unsigned int*)sgilabel, sizeof(*sgilabel)));
1997 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00001998 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00001999
2000 if (lseek(fd, 0, SEEK_SET) < 0)
2001 fdisk_fatal(unable_to_seek);
2002 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
2003 fdisk_fatal(unable_to_write);
2004 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2005 /*
2006 * keep this habit of first writing the "sgilabel".
2007 * I never tested whether it works without (AN 981002).
2008 */
2009 sgiinfo *info = fill_sgiinfo();
2010 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2011 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2012 fdisk_fatal(unable_to_seek);
2013 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2014 fdisk_fatal(unable_to_write);
2015 free(info);
2016 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002017}
2018
2019static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002020compare_start(int *x, int *y)
2021{
2022 /*
2023 * sort according to start sectors
2024 * and prefers largest partition:
2025 * entry zero is entire disk entry
2026 */
2027 unsigned int i = *x;
2028 unsigned int j = *y;
2029 unsigned int a = sgi_get_start_sector(i);
2030 unsigned int b = sgi_get_start_sector(j);
2031 unsigned int c = sgi_get_num_sectors(i);
2032 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002033
Rob Landleyb73451d2006-02-24 16:29:00 +00002034 if (a == b)
2035 return (d > c) ? 1 : (d == c) ? 0 : -1;
2036 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002037}
2038
2039
2040static int
Eric Andersen040f4402003-07-30 08:40:37 +00002041verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002042{
Rob Landleyb73451d2006-02-24 16:29:00 +00002043 int Index[16]; /* list of valid partitions */
2044 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2045 int entire = 0, i = 0;
2046 unsigned int start = 0;
2047 long long gap = 0; /* count unused blocks */
2048 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002049
Rob Landleyb73451d2006-02-24 16:29:00 +00002050 clearfreelist();
2051 for (i = 0; i < 16; i++) {
2052 if (sgi_get_num_sectors(i) != 0) {
2053 Index[sortcount++] = i;
2054 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2055 if (entire++ == 1) {
2056 if (verbose)
2057 printf(_("More than one entire disk entry present.\n"));
2058 }
2059 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002060 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002061 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002062 if (sortcount == 0) {
2063 if (verbose)
2064 printf(_("No partitions defined\n"));
2065 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2066 }
2067 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2068 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2069 if ((Index[0] != 10) && verbose)
2070 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2071 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2072 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002073 "at block 0,\n"
2074 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002075 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002076 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002077 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2078 printf(_("The entire disk partition is only %d diskblock large,\n"
2079 "but the disk is %d diskblocks long.\n"),
2080 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002081 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002082 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002083 if (verbose)
2084 printf(_("One Partition (#11) should cover the entire disk.\n"));
2085 if (debug > 2)
2086 printf("sysid=%d\tpartition=%d\n",
2087 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002088 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002089 for (i = 1, start = 0; i < sortcount; i++) {
2090 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2091
2092 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2093 if (debug) /* I do not understand how some disks fulfil it */
2094 if (verbose)
2095 printf(_("Partition %d does not start on cylinder boundary.\n"),
2096 Index[i]+1);
2097 }
2098 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2099 if (debug) /* I do not understand how some disks fulfil it */
2100 if (verbose)
2101 printf(_("Partition %d does not end on cylinder boundary.\n"),
2102 Index[i]+1);
2103 }
2104 /* We cannot handle several "entire disk" entries. */
2105 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2106 if (start > sgi_get_start_sector(Index[i])) {
2107 if (verbose)
2108 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2109 Index[i-1]+1, Index[i]+1,
2110 start - sgi_get_start_sector(Index[i]));
2111 if (gap > 0) gap = -gap;
2112 if (gap == 0) gap = -1;
2113 }
2114 if (start < sgi_get_start_sector(Index[i])) {
2115 if (verbose)
2116 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2117 sgi_get_start_sector(Index[i]) - start,
2118 start, sgi_get_start_sector(Index[i])-1);
2119 gap += sgi_get_start_sector(Index[i]) - start;
2120 add2freelist(start, sgi_get_start_sector(Index[i]));
2121 }
2122 start = sgi_get_start_sector(Index[i])
2123 + sgi_get_num_sectors(Index[i]);
2124 if (debug > 1) {
2125 if (verbose)
2126 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2127 sgi_get_start_sector(Index[i]),
2128 sgi_get_num_sectors(Index[i]),
2129 sgi_get_sysid(Index[i]));
2130 }
2131 }
2132 if (start < lastblock) {
2133 if (verbose)
2134 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2135 lastblock - start, start, lastblock-1);
2136 gap += lastblock - start;
2137 add2freelist(start, lastblock);
2138 }
2139 /*
2140 * Done with arithmetics
2141 * Go for details now
2142 */
2143 if (verbose) {
2144 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2145 printf(_("\nThe boot partition does not exist.\n"));
2146 }
2147 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2148 printf(_("\nThe swap partition does not exist.\n"));
2149 } else {
2150 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2151 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2152 printf(_("\nThe swap partition has no swap type.\n"));
2153 }
2154 if (sgi_check_bootfile("/unix"))
2155 printf(_("\tYou have chosen an unusual boot file name.\n"));
2156 }
2157 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002158}
2159
2160static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002161sgi_gaps(void)
2162{
2163 /*
2164 * returned value is:
2165 * = 0 : disk is properly filled to the rim
2166 * < 0 : there is an overlap
2167 * > 0 : there is still some vacant space
2168 */
2169 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002170}
2171
2172static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002173sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002174{
Rob Landleyb73451d2006-02-24 16:29:00 +00002175 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2176 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2177 return;
2178 }
2179 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2180 && (sgi_get_start_sector(i) < 1) ) {
2181 read_chars(
2182 _("It is highly recommended that the partition at offset 0\n"
2183 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2184 "retrieve from its directory standalone tools like sash and fx.\n"
2185 "Only the \"SGI volume\" entire disk section may violate this.\n"
2186 "Type YES if you are sure about tagging this partition differently.\n"));
2187 if (strcmp(line_ptr, _("YES\n")))
2188 return;
2189 }
2190 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002191}
2192
2193/* returns partition index of first entry marked as entire disk */
2194static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002195sgi_entire(void)
2196{
2197 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002198
Rob Landleyb73451d2006-02-24 16:29:00 +00002199 for (i = 0; i < 16; i++)
2200 if (sgi_get_sysid(i) == SGI_VOLUME)
2201 return i;
2202 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002203}
2204
2205static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002206sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2207{
2208 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2209 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2210 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2211 set_changed(i);
2212 if (sgi_gaps() < 0) /* rebuild freelist */
2213 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002214}
2215
2216static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002217sgi_set_entire(void)
2218{
2219 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002220
Rob Landleyb73451d2006-02-24 16:29:00 +00002221 for (n = 10; n < partitions; n++) {
2222 if(!sgi_get_num_sectors(n) ) {
2223 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2224 break;
2225 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002226 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002227}
2228
2229static void
2230sgi_set_volhdr(void)
2231{
Rob Landleyb73451d2006-02-24 16:29:00 +00002232 int n;
2233
2234 for (n = 8; n < partitions; n++) {
2235 if (!sgi_get_num_sectors(n)) {
2236 /*
2237 * 5 cylinders is an arbitrary value I like
2238 * IRIX 5.3 stored files in the volume header
2239 * (like sash, symmon, fx, ide) with ca. 3200
2240 * sectors.
2241 */
2242 if (heads * sectors * 5 < sgi_get_lastblock())
2243 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2244 break;
2245 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002246 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002247}
2248
2249static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002250sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002251{
Rob Landleyb73451d2006-02-24 16:29:00 +00002252 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002253}
2254
2255static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002256sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002257{
Rob Landleyb73451d2006-02-24 16:29:00 +00002258 char mesg[256];
2259 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002260
Rob Landleyb73451d2006-02-24 16:29:00 +00002261 if (n == 10) {
2262 sys = SGI_VOLUME;
2263 } else if (n == 8) {
2264 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002265 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002266 if(sgi_get_num_sectors(n)) {
2267 printf(_("Partition %d is already defined. Delete "
2268 "it before re-adding it.\n"), n + 1);
2269 return;
2270 }
2271 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2272 printf(_("Attempting to generate entire disk entry automatically.\n"));
2273 sgi_set_entire();
2274 sgi_set_volhdr();
2275 }
2276 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2277 printf(_("The entire disk is already covered with partitions.\n"));
2278 return;
2279 }
2280 if (sgi_gaps() < 0) {
2281 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2282 return;
2283 }
2284 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2285 while (1) {
2286 if(sys == SGI_VOLUME) {
2287 last = sgi_get_lastblock();
2288 first = read_int(0, 0, last-1, 0, mesg);
2289 if (first != 0) {
2290 printf(_("It is highly recommended that eleventh partition\n"
2291 "covers the entire disk and is of type `SGI volume'\n"));
2292 }
2293 } else {
2294 first = freelist[0].first;
2295 last = freelist[0].last;
2296 first = read_int(scround(first), scround(first), scround(last)-1,
2297 0, mesg);
2298 }
2299 if (display_in_cyl_units)
2300 first *= units_per_sector;
2301 else
2302 first = first; /* align to cylinder if you know how ... */
2303 if(!last )
2304 last = isinfreelist(first);
2305 if(last == 0) {
2306 printf(_("You will get a partition overlap on the disk. "
2307 "Fix it first!\n"));
2308 } else
2309 break;
2310 }
2311 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2312 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2313 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002314 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002315 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002316 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002317 last = last; /* align to cylinder if You know how ... */
2318 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2319 printf(_("It is highly recommended that eleventh partition\n"
2320 "covers the entire disk and is of type `SGI volume'\n"));
2321 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002322}
2323
Eric Andersen040f4402003-07-30 08:40:37 +00002324#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002325static void
2326create_sgilabel(void)
2327{
Rob Landleyb73451d2006-02-24 16:29:00 +00002328 struct hd_geometry geometry;
2329 struct {
2330 unsigned int start;
2331 unsigned int nsect;
2332 int sysid;
2333 } old[4];
2334 int i = 0;
2335 long longsectors; /* the number of sectors on the device */
2336 int res; /* the result from the ioctl */
2337 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002338
Rob Landleyb73451d2006-02-24 16:29:00 +00002339 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002340
Rob Landleyb73451d2006-02-24 16:29:00 +00002341 fprintf( stderr,
2342 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2343 "until you decide to write them. After that, of course, the previous\n"
2344 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002345
Rob Landley2c39eee2006-05-05 16:54:40 +00002346 sgi_other_endian = (BB_LITTLE_ENDIAN);
Rob Landleyb73451d2006-02-24 16:29:00 +00002347 res = ioctl(fd, BLKGETSIZE, &longsectors);
2348 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2349 heads = geometry.heads;
2350 sectors = geometry.sectors;
2351 if (res == 0) {
2352 /* the get device size ioctl was successful */
2353 cylinders = longsectors / (heads * sectors);
2354 cylinders /= sec_fac;
2355 } else {
2356 /* otherwise print error and use truncated version */
2357 cylinders = geometry.cylinders;
2358 fprintf(stderr,
2359 _("Warning: BLKGETSIZE ioctl failed on %s. "
2360 "Using geometry cylinder value of %d.\n"
2361 "This value may be truncated for devices"
2362 " > 33.8 GB.\n"), disk_device, cylinders);
2363 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002364 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002365 for (i = 0; i < 4; i++) {
2366 old[i].sysid = 0;
2367 if (valid_part_table_flag(MBRbuffer)) {
2368 if(get_part_table(i)->sys_ind) {
2369 old[i].sysid = get_part_table(i)->sys_ind;
2370 old[i].start = get_start_sect(get_part_table(i));
2371 old[i].nsect = get_nr_sects(get_part_table(i));
2372 printf(_("Trying to keep parameters of partition %d.\n"), i);
2373 if (debug)
2374 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2375 old[i].sysid, old[i].start, old[i].nsect);
2376 }
2377 }
2378 }
Eric Andersen040f4402003-07-30 08:40:37 +00002379
Rob Landleyb73451d2006-02-24 16:29:00 +00002380 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2381 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2382 sgilabel->boot_part = SGI_SSWAP16(0);
2383 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002384
Rob Landleyb73451d2006-02-24 16:29:00 +00002385 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2386 memset(sgilabel->boot_file, 0, 16);
2387 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002388
Rob Landleyb73451d2006-02-24 16:29:00 +00002389 sgilabel->devparam.skew = (0);
2390 sgilabel->devparam.gap1 = (0);
2391 sgilabel->devparam.gap2 = (0);
2392 sgilabel->devparam.sparecyl = (0);
2393 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2394 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2395 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002396 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002397 sgilabel->devparam.cmd_tag_queue_depth = (0);
2398 sgilabel->devparam.unused0 = (0);
2399 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2400 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002401 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002402 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2403 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2404 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002405 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002406 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2407 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2408 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2409 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2410 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2411 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2412 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2413 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2414 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2415 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2416 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002417 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002418 partitions = 16;
2419 sgi_volumes = 15;
2420 sgi_set_entire();
2421 sgi_set_volhdr();
2422 for (i = 0; i < 4; i++) {
2423 if(old[i].sysid) {
2424 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2425 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002426 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002427}
2428
2429static void
2430sgi_set_xcyl(void)
2431{
Rob Landleyb73451d2006-02-24 16:29:00 +00002432 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002433}
Eric Andersen040f4402003-07-30 08:40:37 +00002434#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002435
2436/* _____________________________________________________________
2437 */
2438
Eric Andersen040f4402003-07-30 08:40:37 +00002439static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002440fill_sgiinfo(void)
2441{
Rob Landleyb73451d2006-02-24 16:29:00 +00002442 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002443
Rob Landleyb73451d2006-02-24 16:29:00 +00002444 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2445 info->b1 = SGI_SSWAP32(-1);
2446 info->b2 = SGI_SSWAP16(-1);
2447 info->b3 = SGI_SSWAP16(1);
2448 /* You may want to replace this string !!!!!!! */
2449 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2450 strcpy( (char*)info->serial, "0000" );
2451 info->check1816 = SGI_SSWAP16(18*256 +16 );
2452 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2453 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002454}
2455#endif /* SGI_LABEL */
2456
2457
2458#ifdef CONFIG_FEATURE_SUN_LABEL
2459/*
2460 * fdisksunlabel.c
2461 *
2462 * I think this is mostly, or entirely, due to
2463 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2464 *
2465 * Merged with fdisk for other architectures, aeb, June 1998.
2466 *
2467 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2468 * Internationalization
2469 */
2470
2471
Rob Landleyb73451d2006-02-24 16:29:00 +00002472static int sun_other_endian;
2473static int scsi_disk;
2474static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002475
2476#ifndef IDE0_MAJOR
2477#define IDE0_MAJOR 3
2478#endif
2479#ifndef IDE1_MAJOR
2480#define IDE1_MAJOR 22
2481#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002482
Rob Landleyb73451d2006-02-24 16:29:00 +00002483static void
2484guess_device_type(void)
2485{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002486 struct stat bootstat;
2487
Rob Landleyb73451d2006-02-24 16:29:00 +00002488 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002489 scsi_disk = 0;
2490 floppy = 0;
2491 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002492 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2493 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002494 scsi_disk = 0;
2495 floppy = 0;
2496 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002497 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002498 scsi_disk = 0;
2499 floppy = 1;
2500 } else {
2501 scsi_disk = 1;
2502 floppy = 0;
2503 }
2504}
2505
2506static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002507 { "\x00" "Empty" }, /* 0 */
2508 { "\x01" "Boot" }, /* 1 */
2509 { "\x02" "SunOS root" }, /* 2 */
2510 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2511 { "\x04" "SunOS usr" }, /* 4 */
2512 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2513 { "\x06" "SunOS stand" }, /* 6 */
2514 { "\x07" "SunOS var" }, /* 7 */
2515 { "\x08" "SunOS home" }, /* 8 */
2516 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2517 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2518 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002519/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002520 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2521 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002522};
2523
2524
2525static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002526set_sun_partition(int i, uint start, uint stop, int sysid)
2527{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002528 sunlabel->infos[i].id = sysid;
2529 sunlabel->partitions[i].start_cylinder =
2530 SUN_SSWAP32(start / (heads * sectors));
2531 sunlabel->partitions[i].num_sectors =
2532 SUN_SSWAP32(stop - start);
2533 set_changed(i);
2534}
2535
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002536static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002537check_sun_label(void)
2538{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002539 unsigned short *ush;
2540 int csum;
2541
Rob Landleyb73451d2006-02-24 16:29:00 +00002542 if (sunlabel->magic != SUN_LABEL_MAGIC
2543 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002544 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002545 sun_other_endian = 0;
2546 return 0;
2547 }
2548 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2549 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2550 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2551 if (csum) {
2552 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2553 "Probably you'll have to set all the values,\n"
2554 "e.g. heads, sectors, cylinders and partitions\n"
2555 "or force a fresh label (s command in main menu)\n"));
2556 } else {
2557 heads = SUN_SSWAP16(sunlabel->ntrks);
2558 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2559 sectors = SUN_SSWAP16(sunlabel->nsect);
2560 }
2561 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002562 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002563 partitions = 8;
2564 return 1;
2565}
2566
2567static const struct sun_predefined_drives {
2568 const char *vendor;
2569 const char *model;
2570 unsigned short sparecyl;
2571 unsigned short ncyl;
2572 unsigned short nacyl;
2573 unsigned short pcylcount;
2574 unsigned short ntrks;
2575 unsigned short nsect;
2576 unsigned short rspeed;
2577} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002578 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2579 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2580 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2581 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2582 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2583 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2584 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2585 { "","SUN0104",1,974,2,1019,6,35,3662},
2586 { "","SUN0207",4,1254,2,1272,9,36,3600},
2587 { "","SUN0327",3,1545,2,1549,9,46,3600},
2588 { "","SUN0340",0,1538,2,1544,6,72,4200},
2589 { "","SUN0424",2,1151,2,2500,9,80,4400},
2590 { "","SUN0535",0,1866,2,2500,7,80,5400},
2591 { "","SUN0669",5,1614,2,1632,15,54,3600},
2592 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2593 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2594 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2595 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2596 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002597};
2598
2599static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002600sun_autoconfigure_scsi(void)
2601{
2602 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002603
2604#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002605 unsigned int id[2];
2606 char buffer[2048];
2607 char buffer2[2048];
2608 FILE *pfd;
2609 char *vendor;
2610 char *model;
2611 char *q;
2612 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002613
Rob Landleyb73451d2006-02-24 16:29:00 +00002614 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2615 sprintf(buffer,
2616 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002617#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002618 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002619#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002620 /* This is very wrong (works only if you have one HBA),
2621 but I haven't found a way how to get hostno
2622 from the current kernel */
2623 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002624#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002625 (id[0]>>16) & 0xff,
2626 id[0] & 0xff,
2627 (id[0]>>8) & 0xff
2628 );
2629 pfd = fopen("/proc/scsi/scsi","r");
2630 if (pfd) {
2631 while (fgets(buffer2, 2048, pfd)) {
2632 if (!strcmp(buffer, buffer2)) {
2633 if (fgets(buffer2,2048,pfd)) {
2634 q = strstr(buffer2,"Vendor: ");
2635 if (q) {
2636 q += 8;
2637 vendor = q;
2638 q = strstr(q," ");
2639 *q++ = 0; /* truncate vendor name */
2640 q = strstr(q,"Model: ");
2641 if (q) {
2642 *q = 0;
2643 q += 7;
2644 model = q;
2645 q = strstr(q," Rev: ");
2646 if (q) {
2647 *q = 0;
2648 for (i = 0; i < SIZE(sun_drives); i++) {
2649 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2650 continue;
2651 if (!strstr(model, sun_drives[i].model))
2652 continue;
2653 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2654 p = sun_drives + i;
2655 break;
2656 }
2657 }
2658 }
2659 }
2660 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002661 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002662 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002663 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002664 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002665 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002666 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002667#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002668 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002669}
2670
Rob Landleyb73451d2006-02-24 16:29:00 +00002671static void
2672create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002673{
2674 struct hd_geometry geometry;
2675 unsigned int ndiv;
2676 int i;
2677 unsigned char c;
2678 const struct sun_predefined_drives *p = NULL;
2679
2680 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002681 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2682 "until you decide to write them. After that, of course, the previous\n"
2683 "content won't be recoverable.\n\n"));
Rob Landley2c39eee2006-05-05 16:54:40 +00002684 sun_other_endian = BB_LITTLE_ENDIAN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002685 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2686 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2687 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002688 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002689 " ? auto configure\n"
2690 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002691 for (i = 0; i < SIZE(sun_drives); i++) {
2692 printf(" %c %s%s%s\n",
2693 i + 'a', sun_drives[i].vendor,
2694 (*sun_drives[i].vendor) ? " " : "",
2695 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002696 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002697 while (1) {
2698 c = read_char(_("Select type (? for auto, 0 for custom): "));
2699 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2700 p = sun_drives + c - 'a';
2701 break;
2702 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2703 p = sun_drives + c - 'A';
2704 break;
2705 } else if (c == '0') {
2706 break;
2707 } else if (c == '?' && scsi_disk) {
2708 p = sun_autoconfigure_scsi();
2709 if (!p)
2710 printf(_("Autoconfigure failed.\n"));
2711 else
2712 break;
2713 }
2714 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002715 }
2716 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002717 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2718 heads = geometry.heads;
2719 sectors = geometry.sectors;
2720 cylinders = geometry.cylinders;
2721 } else {
2722 heads = 0;
2723 sectors = 0;
2724 cylinders = 0;
2725 }
2726 if (floppy) {
2727 sunlabel->nacyl = 0;
2728 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2729 sunlabel->rspeed = SUN_SSWAP16(300);
2730 sunlabel->ilfact = SUN_SSWAP16(1);
2731 sunlabel->sparecyl = 0;
2732 } else {
2733 heads = read_int(1,heads,1024,0,_("Heads"));
2734 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002735 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002736 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002737 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002738 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2739 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2740 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2741 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2742 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2743 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2744 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002745 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002746 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2747 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2748 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2749 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2750 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2751 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2752 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2753 sunlabel->ilfact = SUN_SSWAP16(1);
2754 cylinders = p->ncyl;
2755 heads = p->ntrks;
2756 sectors = p->nsect;
2757 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002758 }
2759
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002760 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002761 "%s%s%s cyl %d alt %d hd %d sec %d",
2762 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2763 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002764 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2765
2766 sunlabel->ntrks = SUN_SSWAP16(heads);
2767 sunlabel->nsect = SUN_SSWAP16(sectors);
2768 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2769 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002770 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002771 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002772 if (cylinders * heads * sectors >= 150 * 2048) {
2773 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2774 } else
2775 ndiv = cylinders * 2 / 3;
2776 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2777 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2778 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002779 }
2780 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2781 {
2782 unsigned short *ush = (unsigned short *)sunlabel;
2783 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002784 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002785 csum ^= *ush++;
2786 sunlabel->csum = csum;
2787 }
2788
2789 set_all_unchanged();
2790 set_changed(0);
2791 get_boot(create_empty_sun);
2792}
2793
2794static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002795toggle_sunflags(int i, unsigned char mask)
2796{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002797 if (sunlabel->infos[i].flags & mask)
2798 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002799 else
2800 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002801 set_changed(i);
2802}
2803
2804static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002805fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2806{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002807 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002808
2809 *start = 0;
2810 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002811 for (i = 0; i < partitions; i++) {
2812 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002813 && sunlabel->infos[i].id
2814 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002815 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2816 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2817 if (continuous) {
2818 if (starts[i] == *start)
2819 *start += lens[i];
2820 else if (starts[i] + lens[i] >= *stop)
2821 *stop = starts[i];
2822 else
2823 continuous = 0;
2824 /* There will be probably more gaps
2825 than one, so lets check afterwards */
2826 }
2827 } else {
2828 starts[i] = 0;
2829 lens[i] = 0;
2830 }
2831 }
2832}
2833
2834static uint *verify_sun_starts;
2835
2836static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002837verify_sun_cmp(int *a, int *b)
2838{
2839 if (*a == -1) return 1;
2840 if (*b == -1) return -1;
2841 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2842 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002843}
2844
2845static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002846verify_sun(void)
2847{
2848 uint starts[8], lens[8], start, stop;
2849 int i,j,k,starto,endo;
2850 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002851
Rob Landleyb73451d2006-02-24 16:29:00 +00002852 verify_sun_starts = starts;
2853 fetch_sun(starts,lens,&start,&stop);
2854 for (k = 0; k < 7; k++) {
2855 for (i = 0; i < 8; i++) {
2856 if (k && (lens[i] % (heads * sectors))) {
2857 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002858 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002859 if (lens[i]) {
2860 for (j = 0; j < i; j++)
2861 if (lens[j]) {
2862 if (starts[j] == starts[i]+lens[i]) {
2863 starts[j] = starts[i]; lens[j] += lens[i];
2864 lens[i] = 0;
2865 } else if (starts[i] == starts[j]+lens[j]){
2866 lens[j] += lens[i];
2867 lens[i] = 0;
2868 } else if (!k) {
2869 if (starts[i] < starts[j]+lens[j]
2870 && starts[j] < starts[i]+lens[i]) {
2871 starto = starts[i];
2872 if (starts[j] > starto)
2873 starto = starts[j];
2874 endo = starts[i]+lens[i];
2875 if (starts[j]+lens[j] < endo)
2876 endo = starts[j]+lens[j];
2877 printf(_("Partition %d overlaps with others in "
2878 "sectors %d-%d\n"), i+1, starto, endo);
2879 }
2880 }
2881 }
2882 }
2883 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002884 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002885 for (i = 0; i < 8; i++) {
2886 if (lens[i])
2887 array[i] = i;
2888 else
2889 array[i] = -1;
2890 }
2891 qsort(array,SIZE(array),sizeof(array[0]),
2892 (int (*)(const void *,const void *)) verify_sun_cmp);
2893 if (array[0] == -1) {
2894 printf(_("No partitions defined\n"));
2895 return;
2896 }
2897 stop = cylinders * heads * sectors;
2898 if (starts[array[0]])
2899 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2900 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2901 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2902 }
2903 start = starts[array[i]] + lens[array[i]];
2904 if (start < stop)
2905 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002906}
2907
2908static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002909add_sun_partition(int n, int sys)
2910{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002911 uint start, stop, stop2;
2912 uint starts[8], lens[8];
2913 int whole_disk = 0;
2914
2915 char mesg[256];
2916 int i, first, last;
2917
2918 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2919 printf(_("Partition %d is already defined. Delete "
2920 "it before re-adding it.\n"), n + 1);
2921 return;
2922 }
2923
2924 fetch_sun(starts,lens,&start,&stop);
2925 if (stop <= start) {
2926 if (n == 2)
2927 whole_disk = 1;
2928 else {
2929 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002930 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002931 return;
2932 }
2933 }
2934 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002935 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002936 if (whole_disk)
2937 first = read_int(0, 0, 0, 0, mesg);
2938 else
2939 first = read_int(scround(start), scround(stop)+1,
2940 scround(stop), 0, mesg);
2941 if (display_in_cyl_units)
2942 first *= units_per_sector;
2943 else
2944 /* Starting sector has to be properly aligned */
2945 first = (first + heads * sectors - 1) / (heads * sectors);
2946 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002947 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002948It is highly recommended that the third partition covers the whole disk\n\
2949and is of type `Whole disk'\n");
2950 /* ewt asks to add: "don't start a partition at cyl 0"
2951 However, edmundo@rano.demon.co.uk writes:
2952 "In addition to having a Sun partition table, to be able to
2953 boot from the disc, the first partition, /dev/sdX1, must
2954 start at cylinder 0. This means that /dev/sdX1 contains
2955 the partition table and the boot block, as these are the
2956 first two sectors of the disc. Therefore you must be
2957 careful what you use /dev/sdX1 for. In particular, you must
2958 not use a partition starting at cylinder 0 for Linux swap,
2959 as that would overwrite the partition table and the boot
2960 block. You may, however, use such a partition for a UFS
2961 or EXT2 file system, as these file systems leave the first
2962 1024 bytes undisturbed. */
2963 /* On the other hand, one should not use partitions
2964 starting at block 0 in an md, or the label will
2965 be trashed. */
2966 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002967 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002968 break;
2969 if (i < partitions && !whole_disk) {
2970 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002971 whole_disk = 1;
2972 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002973 }
2974 printf(_("Sector %d is already allocated\n"), first);
2975 } else
2976 break;
2977 }
2978 stop = cylinders * heads * sectors;
2979 stop2 = stop;
2980 for (i = 0; i < partitions; i++) {
2981 if (starts[i] > first && starts[i] < stop)
2982 stop = starts[i];
2983 }
2984 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002985 _("Last %s or +size or +sizeM or +sizeK"),
2986 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002987 if (whole_disk)
2988 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2989 0, mesg);
2990 else if (n == 2 && !first)
2991 last = read_int(scround(first), scround(stop2), scround(stop2),
2992 scround(first), mesg);
2993 else
2994 last = read_int(scround(first), scround(stop), scround(stop),
2995 scround(first), mesg);
2996 if (display_in_cyl_units)
2997 last *= units_per_sector;
2998 if (n == 2 && !first) {
2999 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003000 whole_disk = 1;
3001 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003002 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003003 printf(_("You haven't covered the whole disk with "
3004 "the 3rd partition, but your value\n"
3005 "%d %s covers some other partition. "
3006 "Your entry has been changed\n"
3007 "to %d %s\n"),
3008 scround(last), str_units(SINGULAR),
3009 scround(stop), str_units(SINGULAR));
3010 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003011 }
3012 } else if (!whole_disk && last > stop)
3013 last = stop;
3014
Rob Landleyb73451d2006-02-24 16:29:00 +00003015 if (whole_disk)
3016 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003017 set_sun_partition(n, first, last, sys);
3018}
3019
3020static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003021sun_delete_partition(int i)
3022{
Eric Andersen040f4402003-07-30 08:40:37 +00003023 unsigned int nsec;
3024
Rob Landleyb73451d2006-02-24 16:29:00 +00003025 if (i == 2
3026 && sunlabel->infos[i].id == WHOLE_DISK
3027 && !sunlabel->partitions[i].start_cylinder
3028 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003029 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003030 "consider leaving this\n"
3031 "partition as Whole disk (5), starting at 0, with %u "
3032 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003033 sunlabel->infos[i].id = 0;
3034 sunlabel->partitions[i].num_sectors = 0;
3035}
3036
3037static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003038sun_change_sysid(int i, int sys)
3039{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003040 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003041 read_chars(
3042 _("It is highly recommended that the partition at offset 0\n"
3043 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3044 "there may destroy your partition table and bootblock.\n"
3045 "Type YES if you're very sure you would like that partition\n"
3046 "tagged with 82 (Linux swap): "));
3047 if (strcmp (line_ptr, _("YES\n")))
3048 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003049 }
3050 switch (sys) {
3051 case SUNOS_SWAP:
3052 case LINUX_SWAP:
3053 /* swaps are not mountable by default */
3054 sunlabel->infos[i].flags |= 0x01;
3055 break;
3056 default:
3057 /* assume other types are mountable;
3058 user can change it anyway */
3059 sunlabel->infos[i].flags &= ~0x01;
3060 break;
3061 }
3062 sunlabel->infos[i].id = sys;
3063}
3064
3065static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003066sun_list_table(int xtra)
3067{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003068 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003069
3070 w = strlen(disk_device);
3071 if (xtra)
3072 printf(
3073 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3074 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3075 "%d extra sects/cyl, interleave %d:1\n"
3076 "%s\n"
3077 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003078 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3079 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3080 SUN_SSWAP16(sunlabel->pcylcount),
3081 SUN_SSWAP16(sunlabel->sparecyl),
3082 SUN_SSWAP16(sunlabel->ilfact),
3083 (char *)sunlabel,
3084 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003085 else
3086 printf(
3087 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3088 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003089 disk_device, heads, sectors, cylinders,
3090 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003091
3092 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003093 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003094 for (i = 0 ; i < partitions; i++) {
3095 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003096 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3097 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003098 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3099 partname(disk_device, i+1, w), /* device */
3100 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3101 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3102 (long) scround(start), /* start */
3103 (long) scround(start+len), /* end */
3104 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3105 sunlabel->infos[i].id, /* type id */
3106 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003107 }
3108 }
3109}
3110
Eric Andersen040f4402003-07-30 08:40:37 +00003111#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3112
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003113static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003114sun_set_alt_cyl(void)
3115{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003116 sunlabel->nacyl =
3117 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003118 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003119}
3120
3121static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003122sun_set_ncyl(int cyl)
3123{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003124 sunlabel->ncyl = SUN_SSWAP16(cyl);
3125}
3126
3127static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003128sun_set_xcyl(void)
3129{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003130 sunlabel->sparecyl =
3131 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003132 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003133}
3134
3135static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003136sun_set_ilfact(void)
3137{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003138 sunlabel->ilfact =
3139 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003140 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003141}
3142
3143static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003144sun_set_rspeed(void)
3145{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003146 sunlabel->rspeed =
3147 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003148 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003149}
3150
3151static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003152sun_set_pcylcount(void)
3153{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003154 sunlabel->pcylcount =
3155 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003156 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003157}
Eric Andersen040f4402003-07-30 08:40:37 +00003158#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003159
3160static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003161sun_write_table(void)
3162{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003163 unsigned short *ush = (unsigned short *)sunlabel;
3164 unsigned short csum = 0;
3165
Rob Landleyb73451d2006-02-24 16:29:00 +00003166 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003167 csum ^= *ush++;
3168 sunlabel->csum = csum;
3169 if (lseek(fd, 0, SEEK_SET) < 0)
3170 fdisk_fatal(unable_to_seek);
3171 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3172 fdisk_fatal(unable_to_write);
3173}
3174#endif /* SUN_LABEL */
3175
3176/* DOS partition types */
3177
3178static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003179 { "\x00" "Empty" },
3180 { "\x01" "FAT12" },
3181 { "\x04" "FAT16 <32M" },
3182 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3183 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3184 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3185 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3186 { "\x0b" "Win95 FAT32" },
3187 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3188 { "\x0e" "Win95 FAT16 (LBA)" },
3189 { "\x0f" "Win95 Ext'd (LBA)" },
3190 { "\x11" "Hidden FAT12" },
3191 { "\x12" "Compaq diagnostics" },
3192 { "\x14" "Hidden FAT16 <32M" },
3193 { "\x16" "Hidden FAT16" },
3194 { "\x17" "Hidden HPFS/NTFS" },
3195 { "\x1b" "Hidden Win95 FAT32" },
3196 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3197 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3198 { "\x3c" "PartitionMagic recovery" },
3199 { "\x41" "PPC PReP Boot" },
3200 { "\x42" "SFS" },
3201 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3202 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3203 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3204 { "\x82" "Linux swap" }, /* also Solaris */
3205 { "\x83" "Linux" },
3206 { "\x84" "OS/2 hidden C: drive" },
3207 { "\x85" "Linux extended" },
3208 { "\x86" "NTFS volume set" },
3209 { "\x87" "NTFS volume set" },
3210 { "\x8e" "Linux LVM" },
3211 { "\x9f" "BSD/OS" }, /* BSDI */
3212 { "\xa0" "IBM Thinkpad hibernation" },
3213 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3214 { "\xa6" "OpenBSD" },
3215 { "\xa8" "Darwin UFS" },
3216 { "\xa9" "NetBSD" },
3217 { "\xab" "Darwin boot" },
3218 { "\xb7" "BSDI fs" },
3219 { "\xb8" "BSDI swap" },
3220 { "\xbe" "Solaris boot" },
3221 { "\xeb" "BeOS fs" },
3222 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3223 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3224 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3225 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3226 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3227 autodetect using persistent
3228 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003229#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003230 { "\x02" "XENIX root" },
3231 { "\x03" "XENIX usr" },
3232 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3233 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3234 { "\x10" "OPUS" },
3235 { "\x18" "AST SmartSleep" },
3236 { "\x24" "NEC DOS" },
3237 { "\x39" "Plan 9" },
3238 { "\x40" "Venix 80286" },
3239 { "\x4d" "QNX4.x" },
3240 { "\x4e" "QNX4.x 2nd part" },
3241 { "\x4f" "QNX4.x 3rd part" },
3242 { "\x50" "OnTrack DM" },
3243 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3244 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3245 { "\x53" "OnTrack DM6 Aux3" },
3246 { "\x54" "OnTrackDM6" },
3247 { "\x55" "EZ-Drive" },
3248 { "\x56" "Golden Bow" },
3249 { "\x5c" "Priam Edisk" },
3250 { "\x61" "SpeedStor" },
3251 { "\x64" "Novell Netware 286" },
3252 { "\x65" "Novell Netware 386" },
3253 { "\x70" "DiskSecure Multi-Boot" },
3254 { "\x75" "PC/IX" },
3255 { "\x93" "Amoeba" },
3256 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3257 { "\xa7" "NeXTSTEP" },
3258 { "\xbb" "Boot Wizard hidden" },
3259 { "\xc1" "DRDOS/sec (FAT-12)" },
3260 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3261 { "\xc6" "DRDOS/sec (FAT-16)" },
3262 { "\xc7" "Syrinx" },
3263 { "\xda" "Non-FS data" },
3264 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003265 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003266 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3267 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3268 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003269 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003270 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3271 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003272 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003273 { "\xf1" "SpeedStor" },
3274 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3275 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3276 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003277#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003278 { 0 }
3279};
3280
3281
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003282
3283/* A valid partition table sector ends in 0x55 0xaa */
3284static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003285part_table_flag(const char *b)
3286{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003287 return ((uint) b[510]) + (((uint) b[511]) << 8);
3288}
3289
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003290
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003291#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003292static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003293write_part_table_flag(char *b)
3294{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003295 b[510] = 0x55;
3296 b[511] = 0xaa;
3297}
3298
3299/* start_sect and nr_sects are stored little endian on all machines */
3300/* moreover, they are not aligned correctly */
3301static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003302store4_little_endian(unsigned char *cp, unsigned int val)
3303{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003304 cp[0] = (val & 0xff);
3305 cp[1] = ((val >> 8) & 0xff);
3306 cp[2] = ((val >> 16) & 0xff);
3307 cp[3] = ((val >> 24) & 0xff);
3308}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003309#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003310
3311static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003312read4_little_endian(const unsigned char *cp)
3313{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003314 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3315 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3316}
3317
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003318#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003319static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003320set_start_sect(struct partition *p, unsigned int start_sect)
3321{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003322 store4_little_endian(p->start4, start_sect);
3323}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003324#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003325
Eric Andersend9261492004-06-28 23:50:31 +00003326static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003327get_start_sect(const struct partition *p)
3328{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003329 return read4_little_endian(p->start4);
3330}
3331
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003332#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003333static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003334set_nr_sects(struct partition *p, int32_t nr_sects)
3335{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003336 store4_little_endian(p->size4, nr_sects);
3337}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003338#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003339
Eric Andersend9261492004-06-28 23:50:31 +00003340static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003341get_nr_sects(const struct partition *p)
3342{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003343 return read4_little_endian(p->size4);
3344}
3345
3346/* normally O_RDWR, -l option gives O_RDONLY */
3347static int type_open = O_RDWR;
3348
3349
Rob Landleyb73451d2006-02-24 16:29:00 +00003350static int ext_index; /* the prime extended partition */
3351static int listing; /* no aborts for fdisk -l */
3352static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003353#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3354static int dos_changed;
3355static int nowarn; /* no warnings for fdisk -l/-s */
3356#endif
3357
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003358
3359
Rob Landleyb73451d2006-02-24 16:29:00 +00003360static uint user_cylinders, user_heads, user_sectors;
3361static uint pt_heads, pt_sectors;
3362static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003363
Eric Andersend9261492004-06-28 23:50:31 +00003364static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003365
Eric Andersen040f4402003-07-30 08:40:37 +00003366static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003367
3368
3369static jmp_buf listingbuf;
3370
Rob Landleyb73451d2006-02-24 16:29:00 +00003371static void fdisk_fatal(enum failure why)
3372{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003373 const char *message;
3374
3375 if (listing) {
3376 close(fd);
3377 longjmp(listingbuf, 1);
3378 }
3379
3380 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003381 case unable_to_open:
3382 message = "Unable to open %s\n";
3383 break;
3384 case unable_to_read:
3385 message = "Unable to read %s\n";
3386 break;
3387 case unable_to_seek:
3388 message = "Unable to seek on %s\n";
3389 break;
3390 case unable_to_write:
3391 message = "Unable to write %s\n";
3392 break;
3393 case ioctl_error:
3394 message = "BLKGETSIZE ioctl failed on %s\n";
3395 break;
3396 default:
3397 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003398 }
3399
3400 fputc('\n', stderr);
3401 fprintf(stderr, message, disk_device);
3402 exit(1);
3403}
3404
3405static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003406seek_sector(off_t secno)
3407{
Eric Andersen0a92f352004-03-30 09:21:54 +00003408 off_t offset = secno * sector_size;
3409 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003410 fdisk_fatal(unable_to_seek);
3411}
3412
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003413#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003414static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003415write_sector(off_t secno, char *buf)
3416{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003417 seek_sector(secno);
3418 if (write(fd, buf, sector_size) != sector_size)
3419 fdisk_fatal(unable_to_write);
3420}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003421#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003422
3423/* Allocate a buffer and read a partition table sector */
3424static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003425read_pte(struct pte *pe, off_t offset)
3426{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003427 pe->offset = offset;
3428 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003429 seek_sector(offset);
3430 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3431 fdisk_fatal(unable_to_read);
3432#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003433 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003434#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003435 pe->part_table = pe->ext_pointer = NULL;
3436}
3437
3438static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003439get_partition_start(const struct pte *pe)
3440{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003441 return pe->offset + get_start_sect(pe->part_table);
3442}
3443
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003444#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003445/*
3446 * Avoid warning about DOS partitions when no DOS partition was changed.
3447 * Here a heuristic "is probably dos partition".
3448 * We might also do the opposite and warn in all cases except
3449 * for "is probably nondos partition".
3450 */
3451static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003452is_dos_partition(int t)
3453{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003454 return (t == 1 || t == 4 || t == 6 ||
3455 t == 0x0b || t == 0x0c || t == 0x0e ||
3456 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3457 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3458 t == 0xc1 || t == 0xc4 || t == 0xc6);
3459}
3460
3461static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003462menu(void)
3463{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003464#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003465 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003466 puts(_("Command action"));
3467 puts(_("\ta\ttoggle a read only flag")); /* sun */
3468 puts(_("\tb\tedit bsd disklabel"));
3469 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3470 puts(_("\td\tdelete a partition"));
3471 puts(_("\tl\tlist known partition types"));
3472 puts(_("\tm\tprint this menu"));
3473 puts(_("\tn\tadd a new partition"));
3474 puts(_("\to\tcreate a new empty DOS partition table"));
3475 puts(_("\tp\tprint the partition table"));
3476 puts(_("\tq\tquit without saving changes"));
3477 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3478 puts(_("\tt\tchange a partition's system id"));
3479 puts(_("\tu\tchange display/entry units"));
3480 puts(_("\tv\tverify the partition table"));
3481 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003482#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003483 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003484#endif
3485 } else
3486#endif
3487#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003488 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003489 puts(_("Command action"));
3490 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3491 puts(_("\tb\tedit bootfile entry")); /* sgi */
3492 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3493 puts(_("\td\tdelete a partition"));
3494 puts(_("\tl\tlist known partition types"));
3495 puts(_("\tm\tprint this menu"));
3496 puts(_("\tn\tadd a new partition"));
3497 puts(_("\to\tcreate a new empty DOS partition table"));
3498 puts(_("\tp\tprint the partition table"));
3499 puts(_("\tq\tquit without saving changes"));
3500 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3501 puts(_("\tt\tchange a partition's system id"));
3502 puts(_("\tu\tchange display/entry units"));
3503 puts(_("\tv\tverify the partition table"));
3504 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003505 } else
3506#endif
3507#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003508 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003509 puts(_("Command action"));
3510 puts(_("\tm\tprint this menu"));
3511 puts(_("\to\tcreate a new empty DOS partition table"));
3512 puts(_("\tq\tquit without saving changes"));
3513 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003514 } else
3515#endif
3516 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003517 puts(_("Command action"));
3518 puts(_("\ta\ttoggle a bootable flag"));
3519 puts(_("\tb\tedit bsd disklabel"));
3520 puts(_("\tc\ttoggle the dos compatibility flag"));
3521 puts(_("\td\tdelete a partition"));
3522 puts(_("\tl\tlist known partition types"));
3523 puts(_("\tm\tprint this menu"));
3524 puts(_("\tn\tadd a new partition"));
3525 puts(_("\to\tcreate a new empty DOS partition table"));
3526 puts(_("\tp\tprint the partition table"));
3527 puts(_("\tq\tquit without saving changes"));
3528 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3529 puts(_("\tt\tchange a partition's system id"));
3530 puts(_("\tu\tchange display/entry units"));
3531 puts(_("\tv\tverify the partition table"));
3532 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003533#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003534 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003535#endif
3536 }
3537}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003538#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3539
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003540
3541#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3542static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003543xmenu(void)
3544{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003545#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003546 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003547 puts(_("Command action"));
3548 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3549 puts(_("\tc\tchange number of cylinders"));
3550 puts(_("\td\tprint the raw data in the partition table"));
3551 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3552 puts(_("\th\tchange number of heads"));
3553 puts(_("\ti\tchange interleave factor")); /*sun*/
3554 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3555 puts(_("\tm\tprint this menu"));
3556 puts(_("\tp\tprint the partition table"));
3557 puts(_("\tq\tquit without saving changes"));
3558 puts(_("\tr\treturn to main menu"));
3559 puts(_("\ts\tchange number of sectors/track"));
3560 puts(_("\tv\tverify the partition table"));
3561 puts(_("\tw\twrite table to disk and exit"));
3562 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003563 } else
3564#endif
3565#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003566 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003567 puts(_("Command action"));
3568 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3569 puts(_("\tc\tchange number of cylinders"));
3570 puts(_("\td\tprint the raw data in the partition table"));
3571 puts(_("\te\tlist extended partitions")); /* !sun */
3572 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3573 puts(_("\th\tchange number of heads"));
3574 puts(_("\tm\tprint this menu"));
3575 puts(_("\tp\tprint the partition table"));
3576 puts(_("\tq\tquit without saving changes"));
3577 puts(_("\tr\treturn to main menu"));
3578 puts(_("\ts\tchange number of sectors/track"));
3579 puts(_("\tv\tverify the partition table"));
3580 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003581 } else
3582#endif
3583#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003584 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003585 puts(_("Command action"));
3586 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3587 puts(_("\tc\tchange number of cylinders"));
3588 puts(_("\td\tprint the raw data in the partition table"));
3589 puts(_("\te\tlist extended partitions")); /* !sun */
3590 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3591 puts(_("\th\tchange number of heads"));
3592 puts(_("\tm\tprint this menu"));
3593 puts(_("\tp\tprint the partition table"));
3594 puts(_("\tq\tquit without saving changes"));
3595 puts(_("\tr\treturn to main menu"));
3596 puts(_("\ts\tchange number of sectors/track"));
3597 puts(_("\tv\tverify the partition table"));
3598 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003599 } else
3600#endif
3601 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003602 puts(_("Command action"));
3603 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3604 puts(_("\tc\tchange number of cylinders"));
3605 puts(_("\td\tprint the raw data in the partition table"));
3606 puts(_("\te\tlist extended partitions")); /* !sun */
3607 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003608#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003609 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003610#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003611 puts(_("\th\tchange number of heads"));
3612 puts(_("\tm\tprint this menu"));
3613 puts(_("\tp\tprint the partition table"));
3614 puts(_("\tq\tquit without saving changes"));
3615 puts(_("\tr\treturn to main menu"));
3616 puts(_("\ts\tchange number of sectors/track"));
3617 puts(_("\tv\tverify the partition table"));
3618 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003619 }
3620}
3621#endif /* ADVANCED mode */
3622
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003623#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003624static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003625get_sys_types(void)
3626{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003627 return (
3628#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003629 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003630#endif
3631#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003632 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003633#endif
3634 i386_sys_types);
3635}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003636#else
3637#define get_sys_types() i386_sys_types
3638#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003639
3640static const char *partition_type(unsigned char type)
3641{
3642 int i;
3643 const struct systypes *types = get_sys_types();
3644
Rob Landleyb73451d2006-02-24 16:29:00 +00003645 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003646 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003647 return types[i].name + 1;
3648
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003649 return _("Unknown");
3650}
3651
3652
3653#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3654static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003655get_sysid(int i)
3656{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003657 return (
3658#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003659 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003660#endif
3661#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003662 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003663#endif
3664 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003665}
3666
3667void list_types(const struct systypes *sys)
3668{
3669 uint last[4], done = 0, next = 0, size;
3670 int i;
3671
3672 for (i = 0; sys[i].name; i++);
3673 size = i;
3674
3675 for (i = 3; i >= 0; i--)
3676 last[3 - i] = done += (size + i - done) / (i + 1);
3677 i = done = 0;
3678
3679 do {
3680 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003681 (unsigned char)sys[next].name[0],
3682 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003683 next = last[i++] + done;
3684 if (i > 3 || next >= last[i]) {
3685 i = 0;
3686 next = ++done;
3687 }
3688 } while (done < last[0]);
3689 putchar('\n');
3690}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003691#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003692
3693static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003694is_cleared_partition(const struct partition *p)
3695{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003696 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3697 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3698 get_start_sect(p) || get_nr_sects(p));
3699}
3700
3701static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003702clear_partition(struct partition *p)
3703{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003704 if (!p)
3705 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003706 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003707}
3708
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003709#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003710static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003711set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3712{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003713 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003714 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003715
3716 if (doext) {
3717 p = ptes[i].ext_pointer;
3718 offset = extended_offset;
3719 } else {
3720 p = ptes[i].part_table;
3721 offset = ptes[i].offset;
3722 }
3723 p->boot_ind = 0;
3724 p->sys_ind = sysid;
3725 set_start_sect(p, start - offset);
3726 set_nr_sects(p, stop - start + 1);
3727 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3728 start = heads*sectors*1024 - 1;
3729 set_hsc(p->head, p->sector, p->cyl, start);
3730 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3731 stop = heads*sectors*1024 - 1;
3732 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3733 ptes[i].changed = 1;
3734}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003735#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003736
3737static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003738test_c(const char **m, const char *mesg)
3739{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003740 int val = 0;
3741 if (!*m)
3742 fprintf(stderr, _("You must set"));
3743 else {
3744 fprintf(stderr, " %s", *m);
3745 val = 1;
3746 }
3747 *m = mesg;
3748 return val;
3749}
3750
3751static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003752warn_geometry(void)
3753{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003754 const char *m = NULL;
3755 int prev = 0;
3756
3757 if (!heads)
3758 prev = test_c(&m, _("heads"));
3759 if (!sectors)
3760 prev = test_c(&m, _("sectors"));
3761 if (!cylinders)
3762 prev = test_c(&m, _("cylinders"));
3763 if (!m)
3764 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003765
3766 fprintf(stderr, "%s%s.\n"
3767#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3768 "You can do this from the extra functions menu.\n"
3769#endif
3770 , prev ? _(" and ") : " ", m);
3771
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003772 return 1;
3773}
3774
3775static void update_units(void)
3776{
3777 int cyl_units = heads * sectors;
3778
3779 if (display_in_cyl_units && cyl_units)
3780 units_per_sector = cyl_units;
3781 else
3782 units_per_sector = 1; /* in sectors */
3783}
3784
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003785#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003786static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003787warn_cylinders(void)
3788{
Rob Landley5527b912006-02-25 03:46:10 +00003789 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003790 fprintf(stderr, _("\n"
3791"The number of cylinders for this disk is set to %d.\n"
3792"There is nothing wrong with that, but this is larger than 1024,\n"
3793"and could in certain setups cause problems with:\n"
3794"1) software that runs at boot time (e.g., old versions of LILO)\n"
3795"2) booting and partitioning software from other OSs\n"
3796" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3797 cylinders);
3798}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003799#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003800
3801static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003802read_extended(int ext)
3803{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003804 int i;
3805 struct pte *pex;
3806 struct partition *p, *q;
3807
3808 ext_index = ext;
3809 pex = &ptes[ext];
3810 pex->ext_pointer = pex->part_table;
3811
3812 p = pex->part_table;
3813 if (!get_start_sect(p)) {
3814 fprintf(stderr,
3815 _("Bad offset in primary extended partition\n"));
3816 return;
3817 }
3818
Rob Landleyb73451d2006-02-24 16:29:00 +00003819 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003820 struct pte *pe = &ptes[partitions];
3821
3822 if (partitions >= MAXIMUM_PARTS) {
3823 /* This is not a Linux restriction, but
3824 this program uses arrays of size MAXIMUM_PARTS.
3825 Do not try to `improve' this test. */
3826 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003827#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003828 fprintf(stderr,
3829 _("Warning: deleting partitions after %d\n"),
3830 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003831 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003832#endif
3833 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003834 return;
3835 }
3836
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003837 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003838
3839 if (!extended_offset)
3840 extended_offset = get_start_sect(p);
3841
3842 q = p = pt_offset(pe->sectorbuffer, 0);
3843 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003844 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003845 if (pe->ext_pointer)
3846 fprintf(stderr,
3847 _("Warning: extra link "
3848 "pointer in partition table"
3849 " %d\n"), partitions + 1);
3850 else
3851 pe->ext_pointer = p;
3852 } else if (p->sys_ind) {
3853 if (pe->part_table)
3854 fprintf(stderr,
3855 _("Warning: ignoring extra "
3856 "data in partition table"
3857 " %d\n"), partitions + 1);
3858 else
3859 pe->part_table = p;
3860 }
3861 }
3862
3863 /* very strange code here... */
3864 if (!pe->part_table) {
3865 if (q != pe->ext_pointer)
3866 pe->part_table = q;
3867 else
3868 pe->part_table = q + 1;
3869 }
3870 if (!pe->ext_pointer) {
3871 if (q != pe->part_table)
3872 pe->ext_pointer = q;
3873 else
3874 pe->ext_pointer = q + 1;
3875 }
3876
3877 p = pe->ext_pointer;
3878 partitions++;
3879 }
3880
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003881#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003882 /* remove empty links */
3883 remove:
3884 for (i = 4; i < partitions; i++) {
3885 struct pte *pe = &ptes[i];
3886
3887 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003888 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003889 printf("omitting empty partition (%d)\n", i+1);
3890 delete_partition(i);
3891 goto remove; /* numbering changed */
3892 }
3893 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003894#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003895}
3896
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003897#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003898static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003899create_doslabel(void)
3900{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003901 int i;
3902
3903 fprintf(stderr,
3904 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3905 "until you decide to write them. After that, of course, the previous\n"
3906 "content won't be recoverable.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00003907
3908 current_label_type = label_dos;
3909
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003910#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003911 possibly_osf_label = 0;
3912#endif
3913 partitions = 4;
3914
3915 for (i = 510-64; i < 510; i++)
3916 MBRbuffer[i] = 0;
3917 write_part_table_flag(MBRbuffer);
3918 extended_offset = 0;
3919 set_all_unchanged();
3920 set_changed(0);
3921 get_boot(create_empty_dos);
3922}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003923#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003924
3925static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003926get_sectorsize(void)
3927{
Rob Landley736e5252006-02-25 03:36:00 +00003928 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003929 int arg;
3930 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3931 sector_size = arg;
3932 if (sector_size != DEFAULT_SECTOR_SIZE)
3933 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003934 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003935 }
3936}
3937
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003938static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003939get_kernel_geometry(void)
3940{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003941 struct hd_geometry geometry;
3942
3943 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3944 kern_heads = geometry.heads;
3945 kern_sectors = geometry.sectors;
3946 /* never use geometry.cylinders - it is truncated */
3947 }
3948}
3949
3950static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003951get_partition_table_geometry(void)
3952{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003953 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003954 struct partition *p;
3955 int i, h, s, hh, ss;
3956 int first = 1;
3957 int bad = 0;
3958
Eric Andersen3496fdc2006-01-30 23:09:20 +00003959 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003960 return;
3961
3962 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003963 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003964 p = pt_offset(bufp, i);
3965 if (p->sys_ind != 0) {
3966 h = p->end_head + 1;
3967 s = (p->end_sector & 077);
3968 if (first) {
3969 hh = h;
3970 ss = s;
3971 first = 0;
3972 } else if (hh != h || ss != s)
3973 bad = 1;
3974 }
3975 }
3976
3977 if (!first && !bad) {
3978 pt_heads = hh;
3979 pt_sectors = ss;
3980 }
3981}
3982
Rob Landleyb73451d2006-02-24 16:29:00 +00003983static void
3984get_geometry(void)
3985{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003986 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003987 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003988
3989 get_sectorsize();
3990 sec_fac = sector_size / 512;
3991#ifdef CONFIG_FEATURE_SUN_LABEL
3992 guess_device_type();
3993#endif
3994 heads = cylinders = sectors = 0;
3995 kern_heads = kern_sectors = 0;
3996 pt_heads = pt_sectors = 0;
3997
3998 get_kernel_geometry();
3999 get_partition_table_geometry();
4000
4001 heads = user_heads ? user_heads :
4002 pt_heads ? pt_heads :
4003 kern_heads ? kern_heads : 255;
4004 sectors = user_sectors ? user_sectors :
4005 pt_sectors ? pt_sectors :
4006 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004007 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4008 /* got bytes */
4009 } else {
4010 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004011
4012 if (ioctl(fd, BLKGETSIZE, &longsectors))
4013 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004014 bytes = ((unsigned long long) longsectors) << 9;
4015 }
4016
4017 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004018
4019 sector_offset = 1;
4020 if (dos_compatible_flag)
4021 sector_offset = sectors;
4022
Eric Andersen040f4402003-07-30 08:40:37 +00004023 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004024 if (!cylinders)
4025 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004026}
4027
4028/*
4029 * Read MBR. Returns:
4030 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4031 * 0: found or created label
4032 * 1: I/O error
4033 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004034static int
4035get_boot(enum action what)
4036{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004037 int i;
4038
4039 partitions = 4;
4040
4041 for (i = 0; i < 4; i++) {
4042 struct pte *pe = &ptes[i];
4043
4044 pe->part_table = pt_offset(MBRbuffer, i);
4045 pe->ext_pointer = NULL;
4046 pe->offset = 0;
4047 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004048#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004049 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004050#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004051 }
4052
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004053#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004054 if (what == create_empty_sun && check_sun_label())
4055 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004056#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004057
4058 memset(MBRbuffer, 0, 512);
4059
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004060#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004061 if (what == create_empty_dos)
4062 goto got_dos_table; /* skip reading disk */
4063
4064 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004065 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4066 if (what == try_only)
4067 return 1;
4068 fdisk_fatal(unable_to_open);
4069 } else
4070 printf(_("You will not be able to write "
4071 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004072 }
4073
4074 if (512 != read(fd, MBRbuffer, 512)) {
4075 if (what == try_only)
4076 return 1;
4077 fdisk_fatal(unable_to_read);
4078 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004079#else
4080 if ((fd = open(disk_device, O_RDONLY)) < 0)
4081 return 1;
4082 if (512 != read(fd, MBRbuffer, 512))
4083 return 1;
4084#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004085
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004086 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004087
4088 update_units();
4089
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004090#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004091 if (check_sun_label())
4092 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004093#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004094
4095#ifdef CONFIG_FEATURE_SGI_LABEL
4096 if (check_sgi_label())
4097 return 0;
4098#endif
4099
4100#ifdef CONFIG_FEATURE_AIX_LABEL
4101 if (check_aix_label())
4102 return 0;
4103#endif
4104
4105#ifdef CONFIG_FEATURE_OSF_LABEL
4106 if (check_osf_label()) {
4107 possibly_osf_label = 1;
4108 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004109 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004110 return 0;
4111 }
4112 printf(_("This disk has both DOS and BSD magic.\n"
4113 "Give the 'b' command to go to BSD mode.\n"));
4114 }
4115#endif
4116
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004117#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004118 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004119#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004120
4121 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004122#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4123 return -1;
4124#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004125 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004126 case fdisk:
4127 fprintf(stderr,
4128 _("Device contains neither a valid DOS "
4129 "partition table, nor Sun, SGI or OSF "
4130 "disklabel\n"));
4131#ifdef __sparc__
4132#ifdef CONFIG_FEATURE_SUN_LABEL
4133 create_sunlabel();
4134#endif
4135#else
4136 create_doslabel();
4137#endif
4138 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004139 case try_only:
4140 return -1;
4141 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004142#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004143 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004144#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004145 break;
4146 default:
4147 fprintf(stderr, _("Internal error\n"));
4148 exit(1);
4149 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004150#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004151 }
4152
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004153#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004154 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004155#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004156 warn_geometry();
4157
4158 for (i = 0; i < 4; i++) {
4159 struct pte *pe = &ptes[i];
4160
Rob Landleyb73451d2006-02-24 16:29:00 +00004161 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004162 if (partitions != 4)
4163 fprintf(stderr, _("Ignoring extra extended "
4164 "partition %d\n"), i + 1);
4165 else
4166 read_extended(i);
4167 }
4168 }
4169
4170 for (i = 3; i < partitions; i++) {
4171 struct pte *pe = &ptes[i];
4172
4173 if (!valid_part_table_flag(pe->sectorbuffer)) {
4174 fprintf(stderr,
4175 _("Warning: invalid flag 0x%04x of partition "
4176 "table %d will be corrected by w(rite)\n"),
4177 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004178#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004179 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004180#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004181 }
4182 }
4183
4184 return 0;
4185}
4186
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004187#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004188/*
4189 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4190 * If the user hits Enter, DFLT is returned.
4191 * Answers like +10 are interpreted as offsets from BASE.
4192 *
4193 * There is no default if DFLT is not between LOW and HIGH.
4194 */
4195static uint
4196read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4197{
4198 uint i;
4199 int default_ok = 1;
4200 static char *ms = NULL;
4201 static int mslen = 0;
4202
4203 if (!ms || strlen(mesg)+100 > mslen) {
4204 mslen = strlen(mesg)+200;
4205 ms = xrealloc(ms,mslen);
4206 }
4207
4208 if (dflt < low || dflt > high)
4209 default_ok = 0;
4210
4211 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004212 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004213 mesg, low, high, dflt);
4214 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004215 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004216
4217 while (1) {
4218 int use_default = default_ok;
4219
4220 /* ask question and read answer */
4221 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004222 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004223 continue;
4224
Eric Andersen84bdea82004-05-19 10:49:17 +00004225 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004226 int minus = (*line_ptr == '-');
4227 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004228
Rob Landleyb73451d2006-02-24 16:29:00 +00004229 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004230
Rob Landleyb73451d2006-02-24 16:29:00 +00004231 while (isdigit(*++line_ptr))
4232 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004233
Rob Landleyb73451d2006-02-24 16:29:00 +00004234 switch (*line_ptr) {
4235 case 'c':
4236 case 'C':
4237 if (!display_in_cyl_units)
4238 i *= heads * sectors;
4239 break;
4240 case 'K':
4241 absolute = 1024;
4242 break;
4243 case 'k':
4244 absolute = 1000;
4245 break;
4246 case 'm':
4247 case 'M':
4248 absolute = 1000000;
4249 break;
4250 case 'g':
4251 case 'G':
4252 absolute = 1000000000;
4253 break;
4254 default:
4255 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004256 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004257 if (absolute) {
4258 unsigned long long bytes;
4259 unsigned long unit;
4260
4261 bytes = (unsigned long long) i * absolute;
4262 unit = sector_size * units_per_sector;
4263 bytes += unit/2; /* round */
4264 bytes /= unit;
4265 i = bytes;
4266 }
4267 if (minus)
4268 i = -i;
4269 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004270 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004271 i = atoi(line_ptr);
4272 while (isdigit(*line_ptr)) {
4273 line_ptr++;
4274 use_default = 0;
4275 }
4276 }
4277 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004278 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004279 if (i >= low && i <= high)
4280 break;
4281 else
4282 printf(_("Value out of range.\n"));
4283 }
4284 return i;
4285}
4286
Rob Landleyb73451d2006-02-24 16:29:00 +00004287static int
4288get_partition(int warn, int max)
4289{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004290 struct pte *pe;
4291 int i;
4292
4293 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4294 pe = &ptes[i];
4295
4296 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004297 if (
4298 (
4299 label_sun != current_label_type &&
4300 label_sgi != current_label_type &&
4301 !pe->part_table->sys_ind
4302 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004303#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004304 || (
4305 label_sun == current_label_type &&
4306 (
4307 !sunlabel->partitions[i].num_sectors
4308 || !sunlabel->infos[i].id
4309 )
4310 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004311#endif
4312#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004313 || (
4314 label_sgi == current_label_type &&
4315 !sgi_get_num_sectors(i)
4316 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004317#endif
Rob Landley5527b912006-02-25 03:46:10 +00004318 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004319 fprintf(stderr,
4320 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004321 i+1
4322 );
4323 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004324 }
4325 return i;
4326}
4327
4328static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004329get_existing_partition(int warn, int max)
4330{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004331 int pno = -1;
4332 int i;
4333
4334 for (i = 0; i < max; i++) {
4335 struct pte *pe = &ptes[i];
4336 struct partition *p = pe->part_table;
4337
4338 if (p && !is_cleared_partition(p)) {
4339 if (pno >= 0)
4340 goto not_unique;
4341 pno = i;
4342 }
4343 }
4344 if (pno >= 0) {
4345 printf(_("Selected partition %d\n"), pno+1);
4346 return pno;
4347 }
4348 printf(_("No partition is defined yet!\n"));
4349 return -1;
4350
4351 not_unique:
4352 return get_partition(warn, max);
4353}
4354
4355static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004356get_nonexisting_partition(int warn, int max)
4357{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004358 int pno = -1;
4359 int i;
4360
4361 for (i = 0; i < max; i++) {
4362 struct pte *pe = &ptes[i];
4363 struct partition *p = pe->part_table;
4364
4365 if (p && is_cleared_partition(p)) {
4366 if (pno >= 0)
4367 goto not_unique;
4368 pno = i;
4369 }
4370 }
4371 if (pno >= 0) {
4372 printf(_("Selected partition %d\n"), pno+1);
4373 return pno;
4374 }
4375 printf(_("All primary partitions have been defined already!\n"));
4376 return -1;
4377
4378 not_unique:
4379 return get_partition(warn, max);
4380}
4381
4382
4383void change_units(void)
4384{
4385 display_in_cyl_units = !display_in_cyl_units;
4386 update_units();
4387 printf(_("Changing display/entry units to %s\n"),
4388 str_units(PLURAL));
4389}
4390
4391static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004392toggle_active(int i)
4393{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004394 struct pte *pe = &ptes[i];
4395 struct partition *p = pe->part_table;
4396
Rob Landleyb73451d2006-02-24 16:29:00 +00004397 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004398 fprintf(stderr,
4399 _("WARNING: Partition %d is an extended partition\n"),
4400 i + 1);
4401 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4402 pe->changed = 1;
4403}
4404
4405static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004406toggle_dos_compatibility_flag(void)
4407{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004408 dos_compatible_flag = ~dos_compatible_flag;
4409 if (dos_compatible_flag) {
4410 sector_offset = sectors;
4411 printf(_("DOS Compatibility flag is set\n"));
4412 }
4413 else {
4414 sector_offset = 1;
4415 printf(_("DOS Compatibility flag is not set\n"));
4416 }
4417}
4418
4419static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004420delete_partition(int i)
4421{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004422 struct pte *pe = &ptes[i];
4423 struct partition *p = pe->part_table;
4424 struct partition *q = pe->ext_pointer;
4425
4426/* Note that for the fifth partition (i == 4) we don't actually
4427 * decrement partitions.
4428 */
4429
4430 if (warn_geometry())
4431 return; /* C/H/S not set */
4432 pe->changed = 1;
4433
4434#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004435 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004436 sun_delete_partition(i);
4437 return;
4438 }
4439#endif
4440#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004441 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004442 sgi_delete_partition(i);
4443 return;
4444 }
4445#endif
4446
4447 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004448 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004449 partitions = 4;
4450 ptes[ext_index].ext_pointer = NULL;
4451 extended_offset = 0;
4452 }
4453 clear_partition(p);
4454 return;
4455 }
4456
4457 if (!q->sys_ind && i > 4) {
4458 /* the last one in the chain - just delete */
4459 --partitions;
4460 --i;
4461 clear_partition(ptes[i].ext_pointer);
4462 ptes[i].changed = 1;
4463 } else {
4464 /* not the last one - further ones will be moved down */
4465 if (i > 4) {
4466 /* delete this link in the chain */
4467 p = ptes[i-1].ext_pointer;
4468 *p = *q;
4469 set_start_sect(p, get_start_sect(q));
4470 set_nr_sects(p, get_nr_sects(q));
4471 ptes[i-1].changed = 1;
4472 } else if (partitions > 5) { /* 5 will be moved to 4 */
4473 /* the first logical in a longer chain */
4474 pe = &ptes[5];
4475
4476 if (pe->part_table) /* prevent SEGFAULT */
4477 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004478 get_partition_start(pe) -
4479 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004480 pe->offset = extended_offset;
4481 pe->changed = 1;
4482 }
4483
4484 if (partitions > 5) {
4485 partitions--;
4486 while (i < partitions) {
4487 ptes[i] = ptes[i+1];
4488 i++;
4489 }
4490 } else
4491 /* the only logical: clear only */
4492 clear_partition(ptes[i].part_table);
4493 }
4494}
4495
4496static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004497change_sysid(void)
4498{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004499 int i, sys, origsys;
4500 struct partition *p;
4501
Eric Andersen040f4402003-07-30 08:40:37 +00004502#ifdef CONFIG_FEATURE_SGI_LABEL
4503 /* If sgi_label then don't use get_existing_partition,
4504 let the user select a partition, since get_existing_partition()
4505 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004506 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004507 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004508 } else {
4509 i = get_partition(0, partitions);
4510 }
4511#else
4512 i = get_existing_partition(0, partitions);
4513#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004514 if (i == -1)
4515 return;
4516 p = ptes[i].part_table;
4517 origsys = sys = get_sysid(i);
4518
4519 /* if changing types T to 0 is allowed, then
4520 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004521 if (!sys && label_sgi != current_label_type &&
4522 label_sun != current_label_type && !get_nr_sects(p))
4523 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004524 printf(_("Partition %d does not exist yet!\n"), i + 1);
Rob Landley5527b912006-02-25 03:46:10 +00004525 }else{
4526 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004527 sys = read_hex (get_sys_types());
4528
Rob Landley5527b912006-02-25 03:46:10 +00004529 if (!sys && label_sgi != current_label_type &&
4530 label_sun != current_label_type)
4531 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004532 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004533 "(but not to Linux). Having partitions of\n"
4534 "type 0 is probably unwise. You can delete\n"
4535 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004536 /* break; */
4537 }
4538
Rob Landley5527b912006-02-25 03:46:10 +00004539 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004540 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004541 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004542 " an extended one or vice versa\n"
4543 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004544 break;
4545 }
4546 }
4547
4548 if (sys < 256) {
4549#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004550 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004551 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004552 "as Whole disk (5),\n"
4553 "as SunOS/Solaris expects it and "
4554 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004555#endif
4556#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004557 if (label_sgi == current_label_type &&
4558 (
4559 (i == 10 && sys != ENTIRE_DISK) ||
4560 (i == 8 && sys != 0)
4561 )
4562 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004563 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004564 "as volume header (0),\nand "
4565 "partition 11 as entire volume (6)"
4566 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004567 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004568#endif
4569 if (sys == origsys)
4570 break;
4571#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004572 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004573 sun_change_sysid(i, sys);
4574 } else
4575#endif
4576#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004577 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004578 sgi_change_sysid(i, sys);
4579 } else
4580#endif
4581 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004582
Rob Landleyb73451d2006-02-24 16:29:00 +00004583 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004584 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004585 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004586 ptes[i].changed = 1;
4587 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004588 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004589 dos_changed = 1;
4590 break;
4591 }
Rob Landley5527b912006-02-25 03:46:10 +00004592 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004593 }
4594}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004595#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4596
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004597
4598/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4599 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4600 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4601 * Lubkin Oct. 1991). */
4602
Rob Landleyb73451d2006-02-24 16:29:00 +00004603static void
4604long2chs(ulong ls, uint *c, uint *h, uint *s)
4605{
4606 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004607
4608 *c = ls / spc;
4609 ls = ls % spc;
4610 *h = ls / sectors;
4611 *s = ls % sectors + 1; /* sectors count from 1 */
4612}
4613
Rob Landleyb73451d2006-02-24 16:29:00 +00004614static void
4615check_consistency(const struct partition *p, int partition)
4616{
4617 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4618 uint pec, peh, pes; /* physical ending c, h, s */
4619 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4620 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004621
4622 if (!heads || !sectors || (partition >= 4))
4623 return; /* do not check extended partitions */
4624
4625/* physical beginning c, h, s */
4626 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4627 pbh = p->head;
4628 pbs = p->sector & 0x3f;
4629
4630/* physical ending c, h, s */
4631 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4632 peh = p->end_head;
4633 pes = p->end_sector & 0x3f;
4634
4635/* compute logical beginning (c, h, s) */
4636 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4637
4638/* compute logical ending (c, h, s) */
4639 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4640
4641/* Same physical / logical beginning? */
4642 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4643 printf(_("Partition %d has different physical/logical "
4644 "beginnings (non-Linux?):\n"), partition + 1);
4645 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4646 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4647 }
4648
4649/* Same physical / logical ending? */
4650 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4651 printf(_("Partition %d has different physical/logical "
4652 "endings:\n"), partition + 1);
4653 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4654 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4655 }
4656
4657#if 0
4658/* Beginning on cylinder boundary? */
4659 if (pbh != !pbc || pbs != 1) {
4660 printf(_("Partition %i does not start on cylinder "
4661 "boundary:\n"), partition + 1);
4662 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4663 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4664 }
4665#endif
4666
4667/* Ending on cylinder boundary? */
4668 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004669 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004670 partition + 1);
4671#if 0
4672 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4673 printf(_("should be (%d, %d, %d)\n"),
4674 pec, heads - 1, sectors);
4675#endif
4676 }
4677}
4678
4679static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004680list_disk_geometry(void)
4681{
Eric Andersen040f4402003-07-30 08:40:37 +00004682 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004683 long megabytes = bytes/1000000;
4684
4685 if (megabytes < 10000)
4686 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004687 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004688 else
4689 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004690 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004691 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004692 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004693 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004694 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004695 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004696 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004697 str_units(PLURAL),
4698 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004699}
4700
4701/*
4702 * Check whether partition entries are ordered by their starting positions.
4703 * Return 0 if OK. Return i if partition i should have been earlier.
4704 * Two separate checks: primary and logical partitions.
4705 */
4706static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004707wrong_p_order(int *prev)
4708{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004709 const struct pte *pe;
4710 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004711 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004712 int i, last_i = 0;
4713
4714 for (i = 0 ; i < partitions; i++) {
4715 if (i == 4) {
4716 last_i = 4;
4717 last_p_start_pos = 0;
4718 }
4719 pe = &ptes[i];
4720 if ((p = pe->part_table)->sys_ind) {
4721 p_start_pos = get_partition_start(pe);
4722
4723 if (last_p_start_pos > p_start_pos) {
4724 if (prev)
4725 *prev = last_i;
4726 return i;
4727 }
4728
4729 last_p_start_pos = p_start_pos;
4730 last_i = i;
4731 }
4732 }
4733 return 0;
4734}
4735
4736#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4737/*
4738 * Fix the chain of logicals.
4739 * extended_offset is unchanged, the set of sectors used is unchanged
4740 * The chain is sorted so that sectors increase, and so that
4741 * starting sectors increase.
4742 *
4743 * After this it may still be that cfdisk doesnt like the table.
4744 * (This is because cfdisk considers expanded parts, from link to
4745 * end of partition, and these may still overlap.)
4746 * Now
4747 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4748 * may help.
4749 */
4750static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004751fix_chain_of_logicals(void)
4752{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004753 int j, oj, ojj, sj, sjj;
4754 struct partition *pj,*pjj,tmp;
4755
4756 /* Stage 1: sort sectors but leave sector of part 4 */
4757 /* (Its sector is the global extended_offset.) */
4758 stage1:
4759 for (j = 5; j < partitions-1; j++) {
4760 oj = ptes[j].offset;
4761 ojj = ptes[j+1].offset;
4762 if (oj > ojj) {
4763 ptes[j].offset = ojj;
4764 ptes[j+1].offset = oj;
4765 pj = ptes[j].part_table;
4766 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4767 pjj = ptes[j+1].part_table;
4768 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4769 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004770 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004771 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004772 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004773 goto stage1;
4774 }
4775 }
4776
4777 /* Stage 2: sort starting sectors */
4778 stage2:
4779 for (j = 4; j < partitions-1; j++) {
4780 pj = ptes[j].part_table;
4781 pjj = ptes[j+1].part_table;
4782 sj = get_start_sect(pj);
4783 sjj = get_start_sect(pjj);
4784 oj = ptes[j].offset;
4785 ojj = ptes[j+1].offset;
4786 if (oj+sj > ojj+sjj) {
4787 tmp = *pj;
4788 *pj = *pjj;
4789 *pjj = tmp;
4790 set_start_sect(pj, ojj+sjj-oj);
4791 set_start_sect(pjj, oj+sj-ojj);
4792 goto stage2;
4793 }
4794 }
4795
4796 /* Probably something was changed */
4797 for (j = 4; j < partitions; j++)
4798 ptes[j].changed = 1;
4799}
4800
4801
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004802static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004803fix_partition_table_order(void)
4804{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004805 struct pte *pei, *pek;
4806 int i,k;
4807
4808 if (!wrong_p_order(NULL)) {
4809 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4810 return;
4811 }
4812
4813 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4814 /* partition i should have come earlier, move it */
4815 /* We have to move data in the MBR */
4816 struct partition *pi, *pk, *pe, pbuf;
4817 pei = &ptes[i];
4818 pek = &ptes[k];
4819
4820 pe = pei->ext_pointer;
4821 pei->ext_pointer = pek->ext_pointer;
4822 pek->ext_pointer = pe;
4823
4824 pi = pei->part_table;
4825 pk = pek->part_table;
4826
4827 memmove(&pbuf, pi, sizeof(struct partition));
4828 memmove(pi, pk, sizeof(struct partition));
4829 memmove(pk, &pbuf, sizeof(struct partition));
4830
4831 pei->changed = pek->changed = 1;
4832 }
4833
4834 if (i)
4835 fix_chain_of_logicals();
4836
4837 printf("Done.\n");
4838
4839}
4840#endif
4841
4842static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004843list_table(int xtra)
4844{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004845 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004846 int i, w;
4847
4848#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004849 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004850 sun_list_table(xtra);
4851 return;
4852 }
4853#endif
4854
4855#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004856 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004857 sgi_list_table(xtra);
4858 return;
4859 }
4860#endif
4861
4862 list_disk_geometry();
4863
4864#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004865 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004866 xbsd_print_disklabel(xtra);
4867 return;
4868 }
4869#endif
4870
4871 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4872 but if the device name ends in a digit, say /dev/foo1,
4873 then the partition is called /dev/foo1p3. */
4874 w = strlen(disk_device);
4875 if (w && isdigit(disk_device[w-1]))
4876 w++;
4877 if (w < 5)
4878 w = 5;
4879
4880 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004881 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004882
4883 for (i = 0; i < partitions; i++) {
4884 const struct pte *pe = &ptes[i];
4885
4886 p = pe->part_table;
4887 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004888 off_t psects = get_nr_sects(p);
4889 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004890 unsigned int podd = 0;
4891
4892 if (sector_size < 1024) {
4893 pblocks /= (1024 / sector_size);
4894 podd = psects % (1024 / sector_size);
4895 }
4896 if (sector_size > 1024)
4897 pblocks *= (sector_size / 1024);
4898 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004899 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004900 partname(disk_device, i+1, w+2),
4901/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4902 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004903/* start */ (unsigned long long) cround(get_partition_start(pe)),
4904/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004905 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004906/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004907/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004908/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004909 check_consistency(p, i);
4910 }
4911 }
4912
4913 /* Is partition table in disk order? It need not be, but... */
4914 /* partition table entries are not checked for correct order if this
4915 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004916 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4917 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004918 printf(_("\nPartition table entries are not in disk order\n"));
4919 }
4920}
4921
4922#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4923static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004924x_list_table(int extend)
4925{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004926 const struct pte *pe;
4927 const struct partition *p;
4928 int i;
4929
4930 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4931 disk_device, heads, sectors, cylinders);
4932 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4933 for (i = 0 ; i < partitions; i++) {
4934 pe = &ptes[i];
4935 p = (extend ? pe->ext_pointer : pe->part_table);
4936 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004937 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004938 i + 1, p->boot_ind, p->head,
4939 sector(p->sector),
4940 cylinder(p->sector, p->cyl), p->end_head,
4941 sector(p->end_sector),
4942 cylinder(p->end_sector, p->end_cyl),
4943 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4944 if (p->sys_ind)
4945 check_consistency(p, i);
4946 }
4947 }
4948}
4949#endif
4950
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004951#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004952static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004953fill_bounds(off_t *first, off_t *last)
4954{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004955 int i;
4956 const struct pte *pe = &ptes[0];
4957 const struct partition *p;
4958
4959 for (i = 0; i < partitions; pe++,i++) {
4960 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004961 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004962 first[i] = 0xffffffff;
4963 last[i] = 0;
4964 } else {
4965 first[i] = get_partition_start(pe);
4966 last[i] = first[i] + get_nr_sects(p) - 1;
4967 }
4968 }
4969}
4970
4971static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004972check(int n, uint h, uint s, uint c, off_t start)
4973{
Eric Andersend9261492004-06-28 23:50:31 +00004974 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004975
4976 real_s = sector(s) - 1;
4977 real_c = cylinder(s, c);
4978 total = (real_c * sectors + real_s) * heads + h;
4979 if (!total)
4980 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4981 if (h >= heads)
4982 fprintf(stderr,
4983 _("Partition %d: head %d greater than maximum %d\n"),
4984 n, h + 1, heads);
4985 if (real_s >= sectors)
4986 fprintf(stderr, _("Partition %d: sector %d greater than "
4987 "maximum %d\n"), n, s, sectors);
4988 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004989 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4990 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004991 if (cylinders <= 1024 && start != total)
4992 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004993 _("Partition %d: previous sectors %llu disagrees with "
4994 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004995}
4996
4997static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004998verify(void)
4999{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005000 int i, j;
5001 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00005002 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005003 struct partition *p;
5004
5005 if (warn_geometry())
5006 return;
5007
5008#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005009 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005010 verify_sun();
5011 return;
5012 }
5013#endif
5014#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005015 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005016 verify_sgi(1);
5017 return;
5018 }
5019#endif
5020
5021 fill_bounds(first, last);
5022 for (i = 0; i < partitions; i++) {
5023 struct pte *pe = &ptes[i];
5024
5025 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005026 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005027 check_consistency(p, i);
5028 if (get_partition_start(pe) < first[i])
5029 printf(_("Warning: bad start-of-data in "
5030 "partition %d\n"), i + 1);
5031 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5032 last[i]);
5033 total += last[i] + 1 - first[i];
5034 for (j = 0; j < i; j++)
5035 if ((first[i] >= first[j] && first[i] <= last[j])
5036 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5037 printf(_("Warning: partition %d overlaps "
5038 "partition %d.\n"), j + 1, i + 1);
5039 total += first[i] >= first[j] ?
5040 first[i] : first[j];
5041 total -= last[i] <= last[j] ?
5042 last[i] : last[j];
5043 }
5044 }
5045 }
5046
5047 if (extended_offset) {
5048 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005049 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005050 get_nr_sects(pex->part_table) - 1;
5051
5052 for (i = 4; i < partitions; i++) {
5053 total++;
5054 p = ptes[i].part_table;
5055 if (!p->sys_ind) {
5056 if (i != 4 || i + 1 < partitions)
5057 printf(_("Warning: partition %d "
5058 "is empty\n"), i + 1);
5059 }
5060 else if (first[i] < extended_offset ||
5061 last[i] > e_last)
5062 printf(_("Logical partition %d not entirely in "
5063 "partition %d\n"), i + 1, ext_index + 1);
5064 }
5065 }
5066
5067 if (total > heads * sectors * cylinders)
5068 printf(_("Total allocated sectors %d greater than the maximum "
5069 "%d\n"), total, heads * sectors * cylinders);
5070 else if ((total = heads * sectors * cylinders - total) != 0)
5071 printf(_("%d unallocated sectors\n"), total);
5072}
5073
5074static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005075add_partition(int n, int sys)
5076{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005077 char mesg[256]; /* 48 does not suffice in Japanese */
5078 int i, readed = 0;
5079 struct partition *p = ptes[n].part_table;
5080 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005081 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005082 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005083 first[partitions], last[partitions];
5084
5085 if (p && p->sys_ind) {
5086 printf(_("Partition %d is already defined. Delete "
5087 "it before re-adding it.\n"), n + 1);
5088 return;
5089 }
5090 fill_bounds(first, last);
5091 if (n < 4) {
5092 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005093 if (display_in_cyl_units || !total_number_of_sectors)
5094 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005095 else
Eric Andersen040f4402003-07-30 08:40:37 +00005096 llimit = total_number_of_sectors - 1;
5097 limit = llimit;
5098 if (limit != llimit)
5099 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005100 if (extended_offset) {
5101 first[ext_index] = extended_offset;
5102 last[ext_index] = get_start_sect(q) +
5103 get_nr_sects(q) - 1;
5104 }
5105 } else {
5106 start = extended_offset + sector_offset;
5107 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5108 }
5109 if (display_in_cyl_units)
5110 for (i = 0; i < partitions; i++)
5111 first[i] = (cround(first[i]) - 1) * units_per_sector;
5112
5113 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5114 do {
5115 temp = start;
5116 for (i = 0; i < partitions; i++) {
5117 int lastplusoff;
5118
5119 if (start == ptes[i].offset)
5120 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005121 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005122 if (start >= first[i] && start <= lastplusoff)
5123 start = lastplusoff + 1;
5124 }
5125 if (start > limit)
5126 break;
5127 if (start >= temp+units_per_sector && readed) {
Eric Andersend9261492004-06-28 23:50:31 +00005128 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005129 temp = start;
5130 readed = 0;
5131 }
5132 if (!readed && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005133 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005134
5135 saved_start = start;
5136 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5137 0, mesg);
5138 if (display_in_cyl_units) {
5139 start = (start - 1) * units_per_sector;
5140 if (start < saved_start) start = saved_start;
5141 }
5142 readed = 1;
5143 }
5144 } while (start != temp || !readed);
5145 if (n > 4) { /* NOT for fifth partition */
5146 struct pte *pe = &ptes[n];
5147
5148 pe->offset = start - sector_offset;
5149 if (pe->offset == extended_offset) { /* must be corrected */
5150 pe->offset++;
5151 if (sector_offset == 1)
5152 start++;
5153 }
5154 }
5155
5156 for (i = 0; i < partitions; i++) {
5157 struct pte *pe = &ptes[i];
5158
5159 if (start < pe->offset && limit >= pe->offset)
5160 limit = pe->offset - 1;
5161 if (start < first[i] && limit >= first[i])
5162 limit = first[i] - 1;
5163 }
5164 if (start > limit) {
5165 printf(_("No free sectors available\n"));
5166 if (n > 4)
5167 partitions--;
5168 return;
5169 }
5170 if (cround(start) == cround(limit)) {
5171 stop = limit;
5172 } else {
5173 snprintf(mesg, sizeof(mesg),
5174 _("Last %s or +size or +sizeM or +sizeK"),
5175 str_units(SINGULAR));
5176 stop = read_int(cround(start), cround(limit), cround(limit),
5177 cround(start), mesg);
5178 if (display_in_cyl_units) {
5179 stop = stop * units_per_sector - 1;
5180 if (stop >limit)
5181 stop = limit;
5182 }
5183 }
5184
5185 set_partition(n, 0, start, stop, sys);
5186 if (n > 4)
5187 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5188
Rob Landleyb73451d2006-02-24 16:29:00 +00005189 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005190 struct pte *pe4 = &ptes[4];
5191 struct pte *pen = &ptes[n];
5192
5193 ext_index = n;
5194 pen->ext_pointer = p;
5195 pe4->offset = extended_offset = start;
5196 pe4->sectorbuffer = xcalloc(1, sector_size);
5197 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5198 pe4->ext_pointer = pe4->part_table + 1;
5199 pe4->changed = 1;
5200 partitions = 5;
5201 }
5202}
5203
5204static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005205add_logical(void)
5206{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005207 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5208 struct pte *pe = &ptes[partitions];
5209
5210 pe->sectorbuffer = xcalloc(1, sector_size);
5211 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5212 pe->ext_pointer = pe->part_table + 1;
5213 pe->offset = 0;
5214 pe->changed = 1;
5215 partitions++;
5216 }
5217 add_partition(partitions - 1, LINUX_NATIVE);
5218}
5219
5220static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005221new_partition(void)
5222{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005223 int i, free_primary = 0;
5224
5225 if (warn_geometry())
5226 return;
5227
5228#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005229 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005230 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5231 return;
5232 }
5233#endif
5234#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005235 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005236 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5237 return;
5238 }
5239#endif
5240#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005241 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005242 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5243 "\n\tIf you want to add DOS-type partitions, create"
5244 "\n\ta new empty DOS partition table first. (Use o.)"
5245 "\n\tWARNING: "
5246 "This will destroy the present disk contents.\n"));
5247 return;
5248 }
5249#endif
5250
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005251 for (i = 0; i < 4; i++)
5252 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005253
Rob Landleyb73451d2006-02-24 16:29:00 +00005254 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005255 printf(_("The maximum number of partitions has been created\n"));
5256 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005257 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005258
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005259 if (!free_primary) {
5260 if (extended_offset)
5261 add_logical();
5262 else
5263 printf(_("You must delete some partition and add "
5264 "an extended partition first\n"));
5265 } else {
5266 char c, line[LINE_LENGTH];
5267 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5268 "partition (1-4)\n",
5269 "Command action", (extended_offset ?
5270 "l logical (5 or over)" : "e extended"));
5271 while (1) {
5272 if ((c = read_char(line)) == 'p' || c == 'P') {
5273 i = get_nonexisting_partition(0, 4);
5274 if (i >= 0)
5275 add_partition(i, LINUX_NATIVE);
5276 return;
5277 }
5278 else if (c == 'l' && extended_offset) {
5279 add_logical();
5280 return;
5281 }
5282 else if (c == 'e' && !extended_offset) {
5283 i = get_nonexisting_partition(0, 4);
5284 if (i >= 0)
5285 add_partition(i, EXTENDED);
5286 return;
5287 }
5288 else
5289 printf(_("Invalid partition number "
5290 "for type `%c'\n"), c);
5291 }
5292 }
5293}
5294
5295static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005296write_table(void)
5297{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005298 int i;
5299
Rob Landley5527b912006-02-25 03:46:10 +00005300 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005301 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005302 if (ptes[i].changed)
5303 ptes[3].changed = 1;
5304 for (i = 3; i < partitions; i++) {
5305 struct pte *pe = &ptes[i];
5306
5307 if (pe->changed) {
5308 write_part_table_flag(pe->sectorbuffer);
5309 write_sector(pe->offset, pe->sectorbuffer);
5310 }
5311 }
5312 }
5313#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005314 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005315 /* no test on change? the printf below might be mistaken */
5316 sgi_write_table();
5317 }
5318#endif
5319#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005320 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005321 int needw = 0;
5322
Rob Landleyb73451d2006-02-24 16:29:00 +00005323 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005324 if (ptes[i].changed)
5325 needw = 1;
5326 if (needw)
5327 sun_write_table();
5328 }
5329#endif
5330
5331 printf(_("The partition table has been altered!\n\n"));
5332 reread_partition_table(1);
5333}
5334
Rob Landleyb73451d2006-02-24 16:29:00 +00005335static void
5336reread_partition_table(int leave)
5337{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005338 int error = 0;
5339 int i;
5340
5341 printf(_("Calling ioctl() to re-read partition table.\n"));
5342 sync();
5343 sleep(2);
5344 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5345 error = errno;
5346 } else {
5347 /* some kernel versions (1.2.x) seem to have trouble
5348 rereading the partition table, but if asked to do it
5349 twice, the second time works. - biro@yggdrasil.com */
5350 sync();
5351 sleep(2);
5352 if ((i = ioctl(fd, BLKRRPART)) != 0)
5353 error = errno;
5354 }
5355
5356 if (i) {
5357 printf(_("\nWARNING: Re-reading the partition table "
5358 "failed with error %d: %s.\n"
5359 "The kernel still uses the old table.\n"
5360 "The new table will be used "
5361 "at the next reboot.\n"),
5362 error, strerror(error));
5363 }
5364
5365 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005366 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005367 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5368 "partitions, please see the fdisk manual page for additional\n"
5369 "information.\n"));
5370
5371 if (leave) {
5372 close(fd);
5373
5374 printf(_("Syncing disks.\n"));
5375 sync();
5376 sleep(4); /* for sync() */
5377 exit(!!i);
5378 }
5379}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005380#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005381
5382#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5383#define MAX_PER_LINE 16
5384static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005385print_buffer(char *pbuffer)
5386{
5387 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005388
5389 for (i = 0, l = 0; i < sector_size; i++, l++) {
5390 if (l == 0)
5391 printf("0x%03X:", i);
5392 printf(" %02X", (unsigned char) pbuffer[i]);
5393 if (l == MAX_PER_LINE - 1) {
5394 printf("\n");
5395 l = -1;
5396 }
5397 }
5398 if (l > 0)
5399 printf("\n");
5400 printf("\n");
5401}
5402
5403
5404static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005405print_raw(void)
5406{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005407 int i;
5408
5409 printf(_("Device: %s\n"), disk_device);
5410#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005411 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005412 print_buffer(MBRbuffer);
5413 else
5414#endif
5415 for (i = 3; i < partitions; i++)
5416 print_buffer(ptes[i].sectorbuffer);
5417}
5418
5419static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005420move_begin(int i)
5421{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005422 struct pte *pe = &ptes[i];
5423 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005424 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005425
5426 if (warn_geometry())
5427 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005428 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005429 printf(_("Partition %d has no data area\n"), i + 1);
5430 return;
5431 }
5432 first = get_partition_start(pe);
5433 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005434 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005435
5436 if (new != get_nr_sects(p)) {
5437 first = get_nr_sects(p) + get_start_sect(p) - new;
5438 set_nr_sects(p, first);
5439 set_start_sect(p, new);
5440 pe->changed = 1;
5441 }
5442}
5443
5444static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005445xselect(void)
5446{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005447 char c;
5448
Rob Landleyb73451d2006-02-24 16:29:00 +00005449 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005450 putchar('\n');
5451 c = tolower(read_char(_("Expert command (m for help): ")));
5452 switch (c) {
5453 case 'a':
5454#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005455 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005456 sun_set_alt_cyl();
5457#endif
5458 break;
5459 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005460 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005461 move_begin(get_partition(0, partitions));
5462 break;
5463 case 'c':
5464 user_cylinders = cylinders =
5465 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005466 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005467#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005468 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005469 sun_set_ncyl(cylinders);
5470#endif
Rob Landley5527b912006-02-25 03:46:10 +00005471 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005472 warn_cylinders();
5473 break;
5474 case 'd':
5475 print_raw();
5476 break;
5477 case 'e':
5478#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005479 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005480 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005481 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005482#endif
5483#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005484 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005485 sun_set_xcyl();
5486 else
5487#endif
Rob Landley5527b912006-02-25 03:46:10 +00005488 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005489 x_list_table(1);
5490 break;
5491 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005492 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005493 fix_partition_table_order();
5494 break;
5495 case 'g':
5496#ifdef CONFIG_FEATURE_SGI_LABEL
5497 create_sgilabel();
5498#endif
5499 break;
5500 case 'h':
5501 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005502 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005503 update_units();
5504 break;
5505 case 'i':
5506#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005507 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005508 sun_set_ilfact();
5509#endif
5510 break;
5511 case 'o':
5512#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005513 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005514 sun_set_rspeed();
5515#endif
5516 break;
5517 case 'p':
5518#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005519 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005520 list_table(1);
5521 else
5522#endif
5523 x_list_table(0);
5524 break;
5525 case 'q':
5526 close(fd);
5527 printf("\n");
5528 exit(0);
5529 case 'r':
5530 return;
5531 case 's':
5532 user_sectors = sectors = read_int(1, sectors, 63, 0,
5533 _("Number of sectors"));
5534 if (dos_compatible_flag) {
5535 sector_offset = sectors;
5536 fprintf(stderr, _("Warning: setting "
5537 "sector offset for DOS "
5538 "compatiblity\n"));
5539 }
5540 update_units();
5541 break;
5542 case 'v':
5543 verify();
5544 break;
5545 case 'w':
5546 write_table(); /* does not return */
5547 break;
5548 case 'y':
5549#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005550 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005551 sun_set_pcylcount();
5552#endif
5553 break;
5554 default:
5555 xmenu();
5556 }
5557 }
5558}
5559#endif /* ADVANCED mode */
5560
5561static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005562is_ide_cdrom_or_tape(const char *device)
5563{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005564 FILE *procf;
5565 char buf[100];
5566 struct stat statbuf;
5567 int is_ide = 0;
5568
5569 /* No device was given explicitly, and we are trying some
5570 likely things. But opening /dev/hdc may produce errors like
5571 "hdc: tray open or drive not ready"
5572 if it happens to be a CD-ROM drive. It even happens that
5573 the process hangs on the attempt to read a music CD.
5574 So try to be careful. This only works since 2.1.73. */
5575
5576 if (strncmp("/dev/hd", device, 7))
5577 return 0;
5578
5579 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5580 procf = fopen(buf, "r");
5581 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5582 is_ide = (!strncmp(buf, "cdrom", 5) ||
5583 !strncmp(buf, "tape", 4));
5584 else
5585 /* Now when this proc file does not exist, skip the
5586 device when it is read-only. */
5587 if (stat(device, &statbuf) == 0)
5588 is_ide = ((statbuf.st_mode & 0222) == 0);
5589
5590 if (procf)
5591 fclose(procf);
5592 return is_ide;
5593}
5594
Rob Landley5527b912006-02-25 03:46:10 +00005595
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005596static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005597try(const char *device, int user_specified)
5598{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005599 int gb;
5600
5601 disk_device = device;
5602 if (setjmp(listingbuf))
5603 return;
5604 if (!user_specified)
5605 if (is_ide_cdrom_or_tape(device))
5606 return;
5607 if ((fd = open(disk_device, type_open)) >= 0) {
5608 gb = get_boot(try_only);
5609 if (gb > 0) { /* I/O error */
5610 close(fd);
5611 } else if (gb < 0) { /* no DOS signature */
5612 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005613 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005614 return;
Rob Landley5527b912006-02-25 03:46:10 +00005615 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005616#ifdef CONFIG_FEATURE_OSF_LABEL
5617 if (btrydev(device) < 0)
5618#endif
5619 fprintf(stderr,
5620 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005621 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005622 close(fd);
5623 } else {
5624 close(fd);
5625 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005626#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005627 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005628 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005629 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005630#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005631 }
5632 } else {
5633 /* Ignore other errors, since we try IDE
5634 and SCSI hard disks which may not be
5635 installed on the system. */
5636 if (errno == EACCES) {
5637 fprintf(stderr, _("Cannot open %s\n"), device);
5638 return;
5639 }
5640 }
5641}
5642
5643/* for fdisk -l: try all things in /proc/partitions
5644 that look like a partition name (do not end in a digit) */
5645static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005646tryprocpt(void)
5647{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005648 FILE *procpt;
5649 char line[100], ptname[100], devname[120], *s;
5650 int ma, mi, sz;
5651
Manuel Novoa III cad53642003-03-19 09:13:01 +00005652 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005653
5654 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005655 if (sscanf(line, " %d %d %d %[^\n ]",
5656 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005657 continue;
5658 for (s = ptname; *s; s++);
5659 if (isdigit(s[-1]))
5660 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005661 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005662 try(devname, 0);
5663 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005664#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005665 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005666#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005667}
5668
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005669#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005670static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005671unknown_command(int c)
5672{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005673 printf(_("%c: unknown command\n"), c);
5674}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005675#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005676
Rob Landleyb73451d2006-02-24 16:29:00 +00005677int fdisk_main(int argc, char **argv)
5678{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005679 int c;
5680#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5681 int optl = 0;
5682#endif
5683#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5684 int opts = 0;
5685#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005686 /*
5687 * Calls:
5688 * fdisk -v
5689 * fdisk -l [-b sectorsize] [-u] device ...
5690 * fdisk -s [partition] ...
5691 * fdisk [-b sectorsize] [-u] device
5692 *
5693 * Options -C, -H, -S set the geometry.
5694 *
5695 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005696 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5697#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5698 "s"
5699#endif
5700 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005701 switch (c) {
5702 case 'b':
5703 /* Ugly: this sector size is really per device,
5704 so cannot be combined with multiple disks,
5705 and te same goes for the C/H/S options.
5706 */
5707 sector_size = atoi(optarg);
5708 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005709 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005710 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005711 sector_offset = 2;
5712 user_set_sector_size = 1;
5713 break;
5714 case 'C':
5715 user_cylinders = atoi(optarg);
5716 break;
5717 case 'H':
5718 user_heads = atoi(optarg);
5719 if (user_heads <= 0 || user_heads >= 256)
5720 user_heads = 0;
5721 break;
5722 case 'S':
5723 user_sectors = atoi(optarg);
5724 if (user_sectors <= 0 || user_sectors >= 64)
5725 user_sectors = 0;
5726 break;
5727 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005728#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005729 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005730#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005731 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005732#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005733 case 's':
5734 opts = 1;
5735 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005736#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005737 case 'u':
5738 display_in_cyl_units = 0;
5739 break;
5740 case 'V':
5741 case 'v':
5742 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5743 return 0;
5744 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005745 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005746 }
5747 }
5748
5749#if 0
5750 printf(_("This kernel finds the sector size itself - "
5751 "-b option ignored\n"));
5752#else
5753 if (user_set_sector_size && argc-optind != 1)
5754 printf(_("Warning: the -b (set sector size) option should"
5755 " be used with one specified device\n"));
5756#endif
5757
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005758#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005759 if (optl) {
5760 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005761#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005762 type_open = O_RDONLY;
5763 if (argc > optind) {
5764 int k;
5765#if __GNUC__
5766 /* avoid gcc warning:
5767 variable `k' might be clobbered by `longjmp' */
5768 (void)&k;
5769#endif
5770 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005771 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005772 try(argv[k], 1);
5773 } else {
5774 /* we no longer have default device names */
5775 /* but, we can use /proc/partitions instead */
5776 tryprocpt();
5777 }
5778 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005779#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005780 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005781#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005782
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005783#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005784 if (opts) {
5785 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005786 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005787
5788 nowarn = 1;
5789 type_open = O_RDONLY;
5790
5791 opts = argc - optind;
5792 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005793 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005794
5795 for (j = optind; j < argc; j++) {
5796 disk_device = argv[j];
5797 if ((fd = open(disk_device, type_open)) < 0)
5798 fdisk_fatal(unable_to_open);
5799 if (ioctl(fd, BLKGETSIZE, &size))
5800 fdisk_fatal(ioctl_error);
5801 close(fd);
5802 if (opts == 1)
5803 printf("%ld\n", size/2);
5804 else
5805 printf("%s: %ld\n", argv[j], size/2);
5806 }
5807 return 0;
5808 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005809#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005810
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005811#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005812 if (argc-optind == 1)
5813 disk_device = argv[optind];
5814 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005815 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005816
5817 get_boot(fdisk);
5818
5819#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005820 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005821 /* OSF label, and no DOS label */
5822 printf(_("Detected an OSF/1 disklabel on %s, entering "
5823 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005824 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005825 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005826 /*Why do we do this? It seems to be counter-intuitive*/
5827 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005828 /* If we return we may want to make an empty DOS label? */
5829 }
5830#endif
5831
5832 while (1) {
5833 putchar('\n');
5834 c = tolower(read_char(_("Command (m for help): ")));
5835 switch (c) {
5836 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005837 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005838 toggle_active(get_partition(1, partitions));
5839#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005840 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005841 toggle_sunflags(get_partition(1, partitions),
5842 0x01);
5843#endif
5844#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005845 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005846 sgi_set_bootpartition(
5847 get_partition(1, partitions));
5848#endif
5849 else
5850 unknown_command(c);
5851 break;
5852 case 'b':
5853#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005854 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005855 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005856 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005857 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005858 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005859 printf(_("Boot file unchanged\n"));
5860 else
5861 sgi_set_bootfile(line_ptr);
5862 } else
5863#endif
5864#ifdef CONFIG_FEATURE_OSF_LABEL
5865 bselect();
5866#endif
5867 break;
5868 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005869 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005870 toggle_dos_compatibility_flag();
5871#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005872 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005873 toggle_sunflags(get_partition(1, partitions),
5874 0x10);
5875#endif
5876#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005877 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005878 sgi_set_swappartition(
5879 get_partition(1, partitions));
5880#endif
5881 else
5882 unknown_command(c);
5883 break;
5884 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005885 {
Eric Andersen040f4402003-07-30 08:40:37 +00005886 int j;
5887#ifdef CONFIG_FEATURE_SGI_LABEL
5888 /* If sgi_label then don't use get_existing_partition,
5889 let the user select a partition, since
5890 get_existing_partition() only works for Linux-like
5891 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005892 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005893 j = get_existing_partition(1, partitions);
5894 } else {
5895 j = get_partition(1, partitions);
5896 }
5897#else
5898 j = get_existing_partition(1, partitions);
5899#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005900 if (j >= 0)
5901 delete_partition(j);
5902 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005903 break;
5904 case 'i':
5905#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005906 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005907 create_sgiinfo();
5908 else
5909#endif
5910 unknown_command(c);
5911 case 'l':
5912 list_types(get_sys_types());
5913 break;
5914 case 'm':
5915 menu();
5916 break;
5917 case 'n':
5918 new_partition();
5919 break;
5920 case 'o':
5921 create_doslabel();
5922 break;
5923 case 'p':
5924 list_table(0);
5925 break;
5926 case 'q':
5927 close(fd);
5928 printf("\n");
5929 return 0;
5930 case 's':
5931#ifdef CONFIG_FEATURE_SUN_LABEL
5932 create_sunlabel();
5933#endif
5934 break;
5935 case 't':
5936 change_sysid();
5937 break;
5938 case 'u':
5939 change_units();
5940 break;
5941 case 'v':
5942 verify();
5943 break;
5944 case 'w':
5945 write_table(); /* does not return */
5946 break;
5947#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5948 case 'x':
5949#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005950 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005951 fprintf(stderr,
5952 _("\n\tSorry, no experts menu for SGI "
5953 "partition tables available.\n\n"));
5954 } else
5955#endif
5956
5957 xselect();
5958 break;
5959#endif
5960 default:
5961 unknown_command(c);
5962 menu();
5963 }
5964 }
5965 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005966#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005967}