blob: 4e23cdb85dec2eebb80b7eb6bc2a9c989bde3d8b [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)
4 *
Rob Landleyb73451d2006-02-24 16:29:00 +00005 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +00006 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru>
7 * initial busybox port, BSD license
8 *
9 * This applet have not the support person from busybox.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000010 */
11
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000012/* Current changes have not compatibility with this version */
Eric Andersen99a75d12003-08-08 20:04:56 +000013#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014
"Vladimir N. Oleynik"5c06b272006-02-25 07:20:15 +000015
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000016#define PROC_PARTITIONS "/proc/partitions"
17
Eric Andersen256c4fd2004-05-19 09:00:00 +000018#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000019#include <sys/types.h>
20#include <sys/stat.h> /* stat */
21#include <ctype.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <errno.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <setjmp.h>
29#include <assert.h> /* assert */
30#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000031#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000032#include <sys/ioctl.h>
33#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000034#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000035
Eric Andersenacd244a2002-12-11 03:49:33 +000036#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
37
38/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000039#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000040
41#include <sys/utsname.h>
42
43#include "busybox.h"
44
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000045#define DKTYPENAMES
46
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000047#define BLKRRPART _IO(0x12,95) /* re-read partition table */
48#define BLKGETSIZE _IO(0x12,96) /* return device size */
49#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
50#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000051
52/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000053 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000054#undef _IOR
55#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000056#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000057
58/*
59 fdisk.h
60*/
61
62#define DEFAULT_SECTOR_SIZE 512
63#define MAX_SECTOR_SIZE 2048
64#define SECTOR_SIZE 512 /* still used in BSD code */
65#define MAXIMUM_PARTS 60
66
67#define ACTIVE_FLAG 0x80
68
69#define EXTENDED 0x05
70#define WIN98_EXTENDED 0x0f
71#define LINUX_PARTITION 0x81
72#define LINUX_SWAP 0x82
73#define LINUX_NATIVE 0x83
74#define LINUX_EXTENDED 0x85
75#define LINUX_LVM 0x8e
76#define LINUX_RAID 0xfd
77
78#define SUNOS_SWAP 3
79#define WHOLE_DISK 5
80
81#define IS_EXTENDED(i) \
82 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
83
84#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
85
86#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
87#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
88
Eric Andersen7495b0d2004-02-06 05:26:58 +000089#ifdef CONFIG_FEATURE_SUN_LABEL
90#define SCSI_IOCTL_GET_IDLUN 0x5382
91#endif
92
Eric Andersend3652bf2003-08-06 09:07:37 +000093
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000094/* including <linux/hdreg.h> also fails */
95struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000096 unsigned char heads;
97 unsigned char sectors;
98 unsigned short cylinders;
99 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000100};
101
102#define HDIO_GETGEO 0x0301 /* get device geometry */
103
104
105struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000106 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000107};
108
Rob Landleyb73451d2006-02-24 16:29:00 +0000109static uint sector_size = DEFAULT_SECTOR_SIZE;
110static uint user_set_sector_size;
111static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000112
113/*
114 * Raw disk label. For DOS-type partition tables the MBR,
115 * with descriptions of the primary partitions.
116 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000117#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000118static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000119#else
120# define MBRbuffer bb_common_bufsiz1
121#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000122
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000123#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000124static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000125#endif
126
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000127static uint heads, sectors, cylinders;
128static void update_units(void);
129
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000130
131/*
132 * return partition name - uses static storage unless buf is supplied
133 */
134static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000135partname(const char *dev, int pno, int lth)
136{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000137 static char buffer[80];
138 const char *p;
139 int w, wp;
140 int bufsiz;
141 char *bufp;
142
143 bufp = buffer;
144 bufsiz = sizeof(buffer);
145
146 w = strlen(dev);
147 p = "";
148
149 if (isdigit(dev[w-1]))
150 p = "p";
151
152 /* devfs kludge - note: fdisk partition names are not supposed
153 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000154 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000155 w -= 4;
156 p = "part";
157 }
158
159 wp = strlen(p);
160
161 if (lth) {
162 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
163 lth-wp-2, w, dev, p, pno);
164 } else {
165 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
166 }
167 return bufp;
168}
169
170struct partition {
171 unsigned char boot_ind; /* 0x80 - active */
172 unsigned char head; /* starting head */
173 unsigned char sector; /* starting sector */
174 unsigned char cyl; /* starting cylinder */
175 unsigned char sys_ind; /* What partition type */
176 unsigned char end_head; /* end head */
177 unsigned char end_sector; /* end sector */
178 unsigned char end_cyl; /* end cylinder */
179 unsigned char start4[4]; /* starting sector counting from 0 */
180 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000181} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000182
183enum failure {
184 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
185 unable_to_write
186};
187
Rob Landley5527b912006-02-25 03:46:10 +0000188enum label_type{
189 label_dos, label_sun, label_sgi, label_aix, label_osf
190};
191
Rob Landleyb73451d2006-02-24 16:29:00 +0000192enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000193
Rob Landley5527b912006-02-25 03:46:10 +0000194static enum label_type current_label_type;
195
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000196static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000197static int fd; /* the disk */
198static int partitions = 4; /* maximum partition + 1 */
199static uint display_in_cyl_units = 1;
200static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000201#ifdef CONFIG_FEATURE_FDISK_WRITABLE
202static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000203static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000204static void reread_partition_table(int leave);
205static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000206static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000207static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000208static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000209#endif
210static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000211static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000212static void get_geometry(void);
213static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000214
215#define PLURAL 0
216#define SINGULAR 1
217
218#define hex_val(c) ({ \
219 char _c = (c); \
220 isdigit(_c) ? _c - '0' : \
221 tolower(_c) + 10 - 'a'; \
222 })
223
224
225#define LINE_LENGTH 800
226#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
227 (n) * sizeof(struct partition)))
228#define sector(s) ((s) & 0x3f)
229#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
230
231#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
232 ((h) + heads * cylinder(s,c)))
233#define set_hsc(h,s,c,sector) { \
234 s = sector % sectors + 1; \
235 sector /= sectors; \
236 h = sector % heads; \
237 sector /= heads; \
238 c = sector & 0xff; \
239 s |= (sector >> 2) & 0xc0; \
240 }
241
242
Eric Andersend9261492004-06-28 23:50:31 +0000243static int32_t get_start_sect(const struct partition *p);
244static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000245
246/*
247 * per partition table entry data
248 *
249 * The four primary partitions have the same sectorbuffer (MBRbuffer)
250 * and have NULL ext_pointer.
251 * Each logical partition table entry has two pointers, one for the
252 * partition and one link to the next one.
253 */
254static struct pte {
255 struct partition *part_table; /* points into sectorbuffer */
256 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000257#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000258 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000259#endif
Eric Andersend9261492004-06-28 23:50:31 +0000260 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000261 char *sectorbuffer; /* disk sector contents */
262} ptes[MAXIMUM_PARTS];
263
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000264
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000265#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000266static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000267set_all_unchanged(void)
268{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000269 int i;
270
271 for (i = 0; i < MAXIMUM_PARTS; i++)
272 ptes[i].changed = 0;
273}
274
275static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000276set_changed(int i)
277{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000278 ptes[i].changed = 1;
279}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000280#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000281
282#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
283static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000284get_part_table(int i)
285{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000286 return ptes[i].part_table;
287}
288#endif
289
290static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000291str_units(int n)
292{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000293 if (n == 1)
294 return display_in_cyl_units ? _("cylinder") : _("sector");
295 else
296 return display_in_cyl_units ? _("cylinders") : _("sectors");
297}
298
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000299static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000300valid_part_table_flag(const char *mbuffer) {
301 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000302 return (b[510] == 0x55 && b[511] == 0xaa);
303}
304
305#ifdef CONFIG_FEATURE_FDISK_WRITABLE
306static char line_buffer[LINE_LENGTH];
307
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000308/* read line; return 0 or first char */
309static int
310read_line(void)
311{
312 static int got_eof = 0;
313
314 fflush (stdout); /* requested by niles@scyld.com */
315 line_ptr = line_buffer;
316 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
317 if (feof(stdin))
318 got_eof++; /* user typed ^D ? */
319 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000320 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
321 exit(1);
322 }
323 return 0;
324 }
325 while (*line_ptr && !isgraph(*line_ptr))
326 line_ptr++;
327 return *line_ptr;
328}
329
330static char
331read_char(const char *mesg)
332{
333 do {
334 fputs(mesg, stdout);
335 } while (!read_line());
336 return *line_ptr;
337}
338
339static char
340read_chars(const char *mesg)
341{
342 fputs(mesg, stdout);
343 if (!read_line()) {
344 *line_ptr = '\n';
345 line_ptr[1] = 0;
346 }
347 return *line_ptr;
348}
349
350static int
351read_hex(const struct systypes *sys)
352{
353 int hex;
354
Rob Landleyb73451d2006-02-24 16:29:00 +0000355 while (1) {
356 read_char(_("Hex code (type L to list codes): "));
357 if (*line_ptr == 'l' || *line_ptr == 'L')
358 list_types(sys);
359 else if (isxdigit (*line_ptr)) {
360 hex = 0;
361 do
362 hex = hex << 4 | hex_val(*line_ptr++);
363 while (isxdigit(*line_ptr));
364 return hex;
365 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000366 }
367}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000368#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000369
370#ifdef CONFIG_FEATURE_AIX_LABEL
371/*
372 * Copyright (C) Andreas Neuper, Sep 1998.
373 * This file may be redistributed under
374 * the terms of the GNU Public License.
375 */
376
377typedef struct {
378 unsigned int magic; /* expect AIX_LABEL_MAGIC */
379 unsigned int fillbytes1[124];
380 unsigned int physical_volume_id;
381 unsigned int fillbytes2[124];
382} aix_partition;
383
384#define AIX_LABEL_MAGIC 0xc9c2d4c1
385#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
386#define AIX_INFO_MAGIC 0x00072959
387#define AIX_INFO_MAGIC_SWAPPED 0x59290700
388
389#define aixlabel ((aix_partition *)MBRbuffer)
390
391
392/*
393 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000394 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
395 * Internationalization
396 *
397 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
398 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000399*/
400
Rob Landleyb73451d2006-02-24 16:29:00 +0000401static int aix_other_endian;
402static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000403
404/*
405 * only dealing with free blocks here
406 */
407
408static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000409aix_info(void)
410{
411 puts(
412 _("\n\tThere is a valid AIX label on this disk.\n"
413 "\tUnfortunately Linux cannot handle these\n"
414 "\tdisks at the moment. Nevertheless some\n"
415 "\tadvice:\n"
416 "\t1. fdisk will destroy its contents on write.\n"
417 "\t2. Be sure that this disk is NOT a still vital\n"
418 "\t part of a volume group. (Otherwise you may\n"
419 "\t erase the other disks as well, if unmirrored.)\n"
420 "\t3. Before deleting this physical volume be sure\n"
421 "\t to remove the disk logically from your AIX\n"
422 "\t machine. (Otherwise you become an AIXpert).")
423 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000424}
425
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000426static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000427check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000428{
Rob Landleyb73451d2006-02-24 16:29:00 +0000429 if (aixlabel->magic != AIX_LABEL_MAGIC &&
430 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +0000431 current_label_type = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +0000432 aix_other_endian = 0;
433 return 0;
434 }
435 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
436 update_units();
Rob Landley5527b912006-02-25 03:46:10 +0000437 current_label_type = label_aix;
Rob Landleyb73451d2006-02-24 16:29:00 +0000438 partitions = 1016;
439 aix_volumes = 15;
440 aix_info();
Rob Landley5527b912006-02-25 03:46:10 +0000441 /*aix_nolabel();*/ /* %% */
442 /*aix_label = 1;*/ /* %% */
Rob Landleyb73451d2006-02-24 16:29:00 +0000443 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000444}
445#endif /* AIX_LABEL */
446
447#ifdef CONFIG_FEATURE_OSF_LABEL
448/*
449 * Copyright (c) 1987, 1988 Regents of the University of California.
450 * All rights reserved.
451 *
452 * Redistribution and use in source and binary forms, with or without
453 * modification, are permitted provided that the following conditions
454 * are met:
455 * 1. Redistributions of source code must retain the above copyright
456 * notice, this list of conditions and the following disclaimer.
457 * 2. Redistributions in binary form must reproduce the above copyright
458 * notice, this list of conditions and the following disclaimer in the
459 * documentation and/or other materials provided with the distribution.
460 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000461 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000462 * This product includes software developed by the University of
463 * California, Berkeley and its contributors.
464 * 4. Neither the name of the University nor the names of its contributors
465 * may be used to endorse or promote products derived from this software
466 * without specific prior written permission.
467 *
468 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
469 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
470 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
471 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
472 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
473 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
474 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
475 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
476 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
477 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
478 * SUCH DAMAGE.
479 */
480
481
482#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000483#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000484#endif
485
486#ifndef BSD_MAXPARTITIONS
487#define BSD_MAXPARTITIONS 16
488#endif
489
490#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
491
492#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
493#define BSD_LABELSECTOR 1
494#define BSD_LABELOFFSET 0
495#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
496#define BSD_LABELSECTOR 0
497#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000498#elif defined (__s390__) || defined (__s390x__)
499#define BSD_LABELSECTOR 1
500#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000501#else
502#error unknown architecture
503#endif
504
505#define BSD_BBSIZE 8192 /* size of boot area, with label */
506#define BSD_SBSIZE 8192 /* max size of fs superblock */
507
508struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000509 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000510 int16_t d_type; /* drive type */
511 int16_t d_subtype; /* controller/d_type specific */
512 char d_typename[16]; /* type name, e.g. "eagle" */
513 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000514 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000515 uint32_t d_secsize; /* # of bytes per sector */
516 uint32_t d_nsectors; /* # of data sectors per track */
517 uint32_t d_ntracks; /* # of tracks per cylinder */
518 uint32_t d_ncylinders; /* # of data cylinders per unit */
519 uint32_t d_secpercyl; /* # of data sectors per cylinder */
520 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000521 /*
522 * Spares (bad sector replacements) below
523 * are not counted in d_nsectors or d_secpercyl.
524 * Spare sectors are assumed to be physical sectors
525 * which occupy space at the end of each track and/or cylinder.
526 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000527 uint16_t d_sparespertrack; /* # of spare sectors per track */
528 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000529 /*
530 * Alternate cylinders include maintenance, replacement,
531 * configuration description areas, etc.
532 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000533 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000534
535 /* hardware characteristics: */
536 /*
537 * d_interleave, d_trackskew and d_cylskew describe perturbations
538 * in the media format used to compensate for a slow controller.
539 * Interleave is physical sector interleave, set up by the formatter
540 * or controller when formatting. When interleaving is in use,
541 * logically adjacent sectors are not physically contiguous,
542 * but instead are separated by some number of sectors.
543 * It is specified as the ratio of physical sectors traversed
544 * per logical sector. Thus an interleave of 1:1 implies contiguous
545 * layout, while 2:1 implies that logical sector 0 is separated
546 * by one sector from logical sector 1.
547 * d_trackskew is the offset of sector 0 on track N
548 * relative to sector 0 on track N-1 on the same cylinder.
549 * Finally, d_cylskew is the offset of sector 0 on cylinder N
550 * relative to sector 0 on cylinder N-1.
551 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000552 uint16_t d_rpm; /* rotational speed */
553 uint16_t d_interleave; /* hardware sector interleave */
554 uint16_t d_trackskew; /* sector 0 skew, per track */
555 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
556 uint32_t d_headswitch; /* head switch time, usec */
557 uint32_t d_trkseek; /* track-to-track seek, usec */
558 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000559#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000560 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000561#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000562 uint32_t d_spare[NSPARE]; /* reserved for future use */
563 uint32_t d_magic2; /* the magic number (again) */
564 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000565 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000566 uint16_t d_npartitions; /* number of partitions in following */
567 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
568 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000569 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000570 uint32_t p_size; /* number of sectors in partition */
571 uint32_t p_offset; /* starting sector */
572 uint32_t p_fsize; /* filesystem basic fragment size */
573 uint8_t p_fstype; /* filesystem type, see below */
574 uint8_t p_frag; /* filesystem fragments per block */
575 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000576 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
577};
578
579/* d_type values: */
580#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
581#define BSD_DTYPE_MSCP 2 /* MSCP */
582#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
583#define BSD_DTYPE_SCSI 4 /* SCSI */
584#define BSD_DTYPE_ESDI 5 /* ESDI interface */
585#define BSD_DTYPE_ST506 6 /* ST506 etc. */
586#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
587#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
588#define BSD_DTYPE_FLOPPY 10 /* floppy */
589
590/* d_subtype values: */
591#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
592#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
593#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
594
595#ifdef DKTYPENAMES
596static const char * const xbsd_dktypenames[] = {
597 "unknown",
598 "SMD",
599 "MSCP",
600 "old DEC",
601 "SCSI",
602 "ESDI",
603 "ST506",
604 "HP-IB",
605 "HP-FL",
606 "type 9",
607 "floppy",
608 0
609};
610#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
611#endif
612
613/*
614 * Filesystem type and version.
615 * Used to interpret other filesystem-specific
616 * per-partition information.
617 */
618#define BSD_FS_UNUSED 0 /* unused */
619#define BSD_FS_SWAP 1 /* swap */
620#define BSD_FS_V6 2 /* Sixth Edition */
621#define BSD_FS_V7 3 /* Seventh Edition */
622#define BSD_FS_SYSV 4 /* System V */
623#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
624#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
625#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
626#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
627#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
628#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
629#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
630#define BSD_FS_ISOFS BSD_FS_ISO9660
631#define BSD_FS_BOOT 13 /* partition contains bootstrap */
632#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
633#define BSD_FS_HFS 15 /* Macintosh HFS */
634#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
635
636/* this is annoying, but it's also the way it is :-( */
637#ifdef __alpha__
638#define BSD_FS_EXT2 8 /* ext2 file system */
639#else
640#define BSD_FS_MSDOS 8 /* MS-DOS file system */
641#endif
642
643#ifdef DKTYPENAMES
644static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000645 { "\x00" "unused" }, /* BSD_FS_UNUSED */
646 { "\x01" "swap" }, /* BSD_FS_SWAP */
647 { "\x02" "Version 6" }, /* BSD_FS_V6 */
648 { "\x03" "Version 7" }, /* BSD_FS_V7 */
649 { "\x04" "System V" }, /* BSD_FS_SYSV */
650 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
651 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
652 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000653#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000654 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000655#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000656 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000657#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000658 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
659 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
660 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
661 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
662 { "\x0d" "boot" }, /* BSD_FS_BOOT */
663 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
664 { "\x0f" "HFS" }, /* BSD_FS_HFS */
665 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
666 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000667};
668#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
669
670#endif
671
672/*
673 * flags shared by various drives:
674 */
675#define BSD_D_REMOVABLE 0x01 /* removable media */
676#define BSD_D_ECC 0x02 /* supports ECC */
677#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
678#define BSD_D_RAMDISK 0x08 /* disk emulator */
679#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
680#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
681
682#endif /* OSF_LABEL */
683
684/*
685 * Copyright (C) Andreas Neuper, Sep 1998.
686 * This file may be modified and redistributed under
687 * the terms of the GNU Public License.
688 */
689
690struct device_parameter { /* 48 bytes */
691 unsigned char skew;
692 unsigned char gap1;
693 unsigned char gap2;
694 unsigned char sparecyl;
695 unsigned short pcylcount;
696 unsigned short head_vol0;
697 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
698 unsigned char cmd_tag_queue_depth;
699 unsigned char unused0;
700 unsigned short unused1;
701 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
702 unsigned short bytes;
703 unsigned short ilfact;
704 unsigned int flags; /* controller flags */
705 unsigned int datarate;
706 unsigned int retries_on_error;
707 unsigned int ms_per_word;
708 unsigned short xylogics_gap1;
709 unsigned short xylogics_syncdelay;
710 unsigned short xylogics_readdelay;
711 unsigned short xylogics_gap2;
712 unsigned short xylogics_readgate;
713 unsigned short xylogics_writecont;
714};
715
716#define SGI_VOLHDR 0x00
717/* 1 and 2 were used for drive types no longer supported by SGI */
718#define SGI_SWAP 0x03
719/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
720#define SGI_VOLUME 0x06
721#define SGI_EFS 0x07
722#define SGI_LVOL 0x08
723#define SGI_RLVOL 0x09
724#define SGI_XFS 0x0a
725#define SGI_XFSLOG 0x0b
726#define SGI_XLV 0x0c
727#define SGI_XVM 0x0d
728#define ENTIRE_DISK SGI_VOLUME
729/*
730 * controller flags
731 */
732#define SECTOR_SLIP 0x01
733#define SECTOR_FWD 0x02
734#define TRACK_FWD 0x04
735#define TRACK_MULTIVOL 0x08
736#define IGNORE_ERRORS 0x10
737#define RESEEK 0x20
738#define ENABLE_CMDTAGQ 0x40
739
740typedef struct {
741 unsigned int magic; /* expect SGI_LABEL_MAGIC */
742 unsigned short boot_part; /* active boot partition */
743 unsigned short swap_part; /* active swap partition */
744 unsigned char boot_file[16]; /* name of the bootfile */
745 struct device_parameter devparam; /* 1 * 48 bytes */
746 struct volume_directory { /* 15 * 16 bytes */
747 unsigned char vol_file_name[8]; /* a character array */
748 unsigned int vol_file_start; /* number of logical block */
749 unsigned int vol_file_size; /* number of bytes */
750 } directory[15];
751 struct sgi_partition { /* 16 * 12 bytes */
752 unsigned int num_sectors; /* number of blocks */
753 unsigned int start_sector; /* must be cylinder aligned */
754 unsigned int id;
755 } partitions[16];
756 unsigned int csum;
757 unsigned int fillbytes;
758} sgi_partition;
759
760typedef struct {
761 unsigned int magic; /* looks like a magic number */
762 unsigned int a2;
763 unsigned int a3;
764 unsigned int a4;
765 unsigned int b1;
766 unsigned short b2;
767 unsigned short b3;
768 unsigned int c[16];
769 unsigned short d[3];
770 unsigned char scsi_string[50];
771 unsigned char serial[137];
772 unsigned short check1816;
773 unsigned char installer[225];
774} sgiinfo;
775
776#define SGI_LABEL_MAGIC 0x0be5a941
777#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
778#define SGI_INFO_MAGIC 0x00072959
779#define SGI_INFO_MAGIC_SWAPPED 0x59290700
780#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000781 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000782#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000783 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000784
785#define sgilabel ((sgi_partition *)MBRbuffer)
786#define sgiparam (sgilabel->devparam)
787
788typedef struct {
789 unsigned char info[128]; /* Informative text string */
790 unsigned char spare0[14];
791 struct sun_info {
792 unsigned char spare1;
793 unsigned char id;
794 unsigned char spare2;
795 unsigned char flags;
796 } infos[8];
797 unsigned char spare1[246]; /* Boot information etc. */
798 unsigned short rspeed; /* Disk rotational speed */
799 unsigned short pcylcount; /* Physical cylinder count */
800 unsigned short sparecyl; /* extra sects per cylinder */
801 unsigned char spare2[4]; /* More magic... */
802 unsigned short ilfact; /* Interleave factor */
803 unsigned short ncyl; /* Data cylinder count */
804 unsigned short nacyl; /* Alt. cylinder count */
805 unsigned short ntrks; /* Tracks per cylinder */
806 unsigned short nsect; /* Sectors per track */
807 unsigned char spare3[4]; /* Even more magic... */
808 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000809 uint32_t start_cylinder;
810 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000811 } partitions[8];
812 unsigned short magic; /* Magic number */
813 unsigned short csum; /* Label xor'd checksum */
814} sun_partition;
815
Eric Andersen040f4402003-07-30 08:40:37 +0000816
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000817#define SUN_LABEL_MAGIC 0xDABE
818#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
819#define sunlabel ((sun_partition *)MBRbuffer)
820#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000821 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000822#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000823 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000824
Eric Andersend3652bf2003-08-06 09:07:37 +0000825
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000826#ifdef CONFIG_FEATURE_OSF_LABEL
827/*
828 Changes:
829 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
830
831 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
832 support for OSF/1 disklabels on Alpha.
833 Also fixed unaligned accesses in alpha_bootblock_checksum()
834*/
835
836#define FREEBSD_PARTITION 0xa5
837#define NETBSD_PARTITION 0xa9
838
Rob Landleyb73451d2006-02-24 16:29:00 +0000839static void xbsd_delete_part(void);
840static void xbsd_new_part(void);
841static void xbsd_write_disklabel(void);
842static int xbsd_create_disklabel(void);
843static void xbsd_edit_disklabel(void);
844static void xbsd_write_bootstrap(void);
845static void xbsd_change_fstype(void);
846static int xbsd_get_part_index(int max);
847static int xbsd_check_new_partition(int *i);
848static void xbsd_list_types(void);
849static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
850static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
851static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
852static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000853
854#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000855static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000856#endif
857
858#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000859static int xbsd_translate_fstype(int linux_type);
860static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000861static struct partition *xbsd_part;
862static int xbsd_part_index;
863#endif
864
865#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000866/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000867static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000868#else
869static char disklabelbuffer[BSD_BBSIZE];
870#endif
871
872static struct xbsd_disklabel xbsd_dlabel;
873
874#define bsd_cround(n) \
875 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
876
877/*
878 * Test whether the whole disk has BSD disk label magic.
879 *
880 * Note: often reformatting with DOS-type label leaves the BSD magic,
881 * so this does not mean that there is a BSD disk label.
882 */
883static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000884check_osf_label(void)
885{
886 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000887 return 0;
888 return 1;
889}
890
891static void xbsd_print_disklabel(int);
892
893static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000894btrydev(const char * dev)
895{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000896 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
897 return -1;
898 printf(_("\nBSD label for device: %s\n"), dev);
899 xbsd_print_disklabel (0);
900 return 0;
901}
902
903static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000904bmenu(void)
905{
906 puts (_("Command action"));
907 puts (_("\td\tdelete a BSD partition"));
908 puts (_("\te\tedit drive data"));
909 puts (_("\ti\tinstall bootstrap"));
910 puts (_("\tl\tlist known filesystem types"));
911 puts (_("\tm\tprint this menu"));
912 puts (_("\tn\tadd a new BSD partition"));
913 puts (_("\tp\tprint BSD partition table"));
914 puts (_("\tq\tquit without saving changes"));
915 puts (_("\tr\treturn to main menu"));
916 puts (_("\ts\tshow complete disklabel"));
917 puts (_("\tt\tchange a partition's filesystem id"));
918 puts (_("\tu\tchange units (cylinders/sectors)"));
919 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000920#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000921 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000922#endif
923}
924
925#if !defined (__alpha__)
926static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000927hidden(int type)
928{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000929 return type ^ 0x10;
930}
931
932static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000933is_bsd_partition_type(int type)
934{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000935 return (type == FREEBSD_PARTITION ||
936 type == hidden(FREEBSD_PARTITION) ||
937 type == NETBSD_PARTITION ||
938 type == hidden(NETBSD_PARTITION));
939}
940#endif
941
942static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000943bselect(void)
944{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000945#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000946 int t, ss;
947 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000948
Rob Landleyb73451d2006-02-24 16:29:00 +0000949 for (t = 0; t < 4; t++) {
950 p = get_part_table(t);
951 if (p && is_bsd_partition_type(p->sys_ind)) {
952 xbsd_part = p;
953 xbsd_part_index = t;
954 ss = get_start_sect(xbsd_part);
955 if (ss == 0) {
956 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
957 partname(disk_device, t+1, 0));
958 return;
959 }
960 printf(_("Reading disklabel of %s at sector %d.\n"),
961 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
962 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
963 if (xbsd_create_disklabel() == 0)
964 return;
965 break;
966 }
967 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000968
Rob Landleyb73451d2006-02-24 16:29:00 +0000969 if (t == 4) {
970 printf(_("There is no *BSD partition on %s.\n"), disk_device);
971 return;
972 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000973
974#elif defined (__alpha__)
975
Rob Landleyb73451d2006-02-24 16:29:00 +0000976 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
977 if (xbsd_create_disklabel() == 0)
978 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000979
980#endif
981
Rob Landleyb73451d2006-02-24 16:29:00 +0000982 while (1) {
983 putchar('\n');
984 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
985 case 'd':
986 xbsd_delete_part();
987 break;
988 case 'e':
989 xbsd_edit_disklabel();
990 break;
991 case 'i':
992 xbsd_write_bootstrap();
993 break;
994 case 'l':
995 xbsd_list_types();
996 break;
997 case 'n':
998 xbsd_new_part();
999 break;
1000 case 'p':
1001 xbsd_print_disklabel(0);
1002 break;
1003 case 'q':
1004 close(fd);
1005 exit(EXIT_SUCCESS);
1006 case 'r':
1007 return;
1008 case 's':
1009 xbsd_print_disklabel(1);
1010 break;
1011 case 't':
1012 xbsd_change_fstype();
1013 break;
1014 case 'u':
1015 change_units();
1016 break;
1017 case 'w':
1018 xbsd_write_disklabel();
1019 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001020#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001021 case 'x':
1022 xbsd_link_part();
1023 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001024#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001025 default:
1026 bmenu();
1027 break;
1028 }
1029 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001030}
1031
1032static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001033xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001034{
Rob Landleyb73451d2006-02-24 16:29:00 +00001035 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001036
Rob Landleyb73451d2006-02-24 16:29:00 +00001037 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1038 xbsd_dlabel.d_partitions[i].p_size = 0;
1039 xbsd_dlabel.d_partitions[i].p_offset = 0;
1040 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1041 if (xbsd_dlabel.d_npartitions == i + 1)
1042 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1043 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001044}
1045
1046static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001047xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001048{
Rob Landleyb73451d2006-02-24 16:29:00 +00001049 off_t begin, end;
1050 char mesg[256];
1051 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001052
Rob Landleyb73451d2006-02-24 16:29:00 +00001053 if (!xbsd_check_new_partition(&i))
1054 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001055
1056#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001057 begin = get_start_sect(xbsd_part);
1058 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001059#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001060 begin = 0;
1061 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001062#endif
1063
Rob Landleyb73451d2006-02-24 16:29:00 +00001064 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1065 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1066 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001067
Rob Landleyb73451d2006-02-24 16:29:00 +00001068 if (display_in_cyl_units)
1069 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001070
Rob Landleyb73451d2006-02-24 16:29:00 +00001071 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1072 str_units(SINGULAR));
1073 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1074 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001075
Rob Landleyb73451d2006-02-24 16:29:00 +00001076 if (display_in_cyl_units)
1077 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001078
Rob Landleyb73451d2006-02-24 16:29:00 +00001079 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1080 xbsd_dlabel.d_partitions[i].p_offset = begin;
1081 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001082}
1083
1084static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001085xbsd_print_disklabel(int show_all)
1086{
1087 struct xbsd_disklabel *lp = &xbsd_dlabel;
1088 struct xbsd_partition *pp;
1089 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001090
Rob Landleyb73451d2006-02-24 16:29:00 +00001091 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001092#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001093 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001094#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001095 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001096#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001097 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1098 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1099 else
1100 printf(_("type: %d\n"), lp->d_type);
1101 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1102 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1103 printf(_("flags:"));
1104 if (lp->d_flags & BSD_D_REMOVABLE)
1105 printf(_(" removable"));
1106 if (lp->d_flags & BSD_D_ECC)
1107 printf(_(" ecc"));
1108 if (lp->d_flags & BSD_D_BADSECT)
1109 printf(_(" badsect"));
1110 printf("\n");
1111 /* On various machines the fields of *lp are short/int/long */
1112 /* In order to avoid problems, we cast them all to long. */
1113 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1114 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1115 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1116 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1117 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1118 printf(_("rpm: %d\n"), lp->d_rpm);
1119 printf(_("interleave: %d\n"), lp->d_interleave);
1120 printf(_("trackskew: %d\n"), lp->d_trackskew);
1121 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1122 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1123 (long) lp->d_headswitch);
1124 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1125 (long) lp->d_trkseek);
1126 printf(_("drivedata: "));
1127 for (i = NDDATA - 1; i >= 0; i--)
1128 if (lp->d_drivedata[i])
1129 break;
1130 if (i < 0)
1131 i = 0;
1132 for (j = 0; j <= i; j++)
1133 printf("%ld ", (long) lp->d_drivedata[j]);
1134 }
1135 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1136 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1137 pp = lp->d_partitions;
1138 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1139 if (pp->p_size) {
1140 if (display_in_cyl_units && lp->d_secpercyl) {
1141 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1142 'a' + i,
1143 (long) pp->p_offset / lp->d_secpercyl + 1,
1144 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1145 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1146 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1147 (long) pp->p_size / lp->d_secpercyl,
1148 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1149 );
1150 } else {
1151 printf(" %c: %8ld %8ld %8ld ",
1152 'a' + i,
1153 (long) pp->p_offset,
1154 (long) pp->p_offset + pp->p_size - 1,
1155 (long) pp->p_size
1156 );
1157 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001158
Rob Landleyb73451d2006-02-24 16:29:00 +00001159 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1160 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1161 else
1162 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001163
Rob Landleyb73451d2006-02-24 16:29:00 +00001164 switch (pp->p_fstype) {
1165 case BSD_FS_UNUSED:
1166 printf(" %5ld %5ld %5.5s ",
1167 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1168 break;
1169 case BSD_FS_BSDFFS:
1170 printf(" %5ld %5ld %5d ",
1171 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1172 break;
1173 default:
1174 printf("%22.22s", "");
1175 break;
1176 }
1177 printf("\n");
1178 }
1179 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001180}
1181
1182static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001183xbsd_write_disklabel(void)
1184{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001185#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001186 printf(_("Writing disklabel to %s.\n"), disk_device);
1187 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001188#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001189 printf(_("Writing disklabel to %s.\n"),
1190 partname(disk_device, xbsd_part_index + 1, 0));
1191 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001192#endif
1193 reread_partition_table(0); /* no exit yet */
1194}
1195
1196static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001197xbsd_create_disklabel(void)
1198{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001199 char c;
1200
1201#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001202 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001203#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001204 fprintf(stderr, _("%s contains no disklabel.\n"),
1205 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001206#endif
1207
1208 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001209 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001210 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001211 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001212#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001213 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001214 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001215#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001216 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001217#endif
1218 ) == 1) {
1219 xbsd_print_disklabel (1);
1220 return 1;
1221 } else
1222 return 0;
1223 } else if (c == 'n')
1224 return 0;
1225 }
1226}
1227
1228static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001229edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001230{
Rob Landleyb73451d2006-02-24 16:29:00 +00001231 do {
1232 fputs(mesg, stdout);
1233 printf(" (%d): ", def);
1234 if (!read_line())
1235 return def;
1236 }
1237 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1238 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001239}
1240
1241static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001242xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001243{
Rob Landleyb73451d2006-02-24 16:29:00 +00001244 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001245
Rob Landleyb73451d2006-02-24 16:29:00 +00001246 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001247
1248#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001249 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1250 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1251 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1252 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001253#endif
1254
Rob Landleyb73451d2006-02-24 16:29:00 +00001255 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1256 while (1) {
1257 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1258 _("sectors/cylinder"));
1259 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1260 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001261
Rob Landleyb73451d2006-02-24 16:29:00 +00001262 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1263 }
1264 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1265 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1266 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1267 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1268 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1269 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001270
Rob Landleyb73451d2006-02-24 16:29:00 +00001271 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001272}
1273
1274static int
1275xbsd_get_bootstrap (char *path, void *ptr, int size)
1276{
Rob Landleyb73451d2006-02-24 16:29:00 +00001277 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001278
Rob Landleyb73451d2006-02-24 16:29:00 +00001279 if ((fdb = open (path, O_RDONLY)) < 0) {
1280 perror(path);
1281 return 0;
1282 }
1283 if (read(fdb, ptr, size) < 0) {
1284 perror(path);
1285 close(fdb);
1286 return 0;
1287 }
1288 printf(" ... %s\n", path);
1289 close(fdb);
1290 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291}
1292
1293static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001294sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001295{
Rob Landleyb73451d2006-02-24 16:29:00 +00001296 printf(_("\nSyncing disks.\n"));
1297 sync();
1298 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001299}
1300
1301static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001302xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001303{
Rob Landleyb73451d2006-02-24 16:29:00 +00001304 char *bootdir = BSD_LINUX_BOOTDIR;
1305 char path[MAXPATHLEN];
1306 char *dkbasename;
1307 struct xbsd_disklabel dl;
1308 char *d, *p, *e;
1309 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001310
Rob Landleyb73451d2006-02-24 16:29:00 +00001311 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1312 dkbasename = "sd";
1313 else
1314 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001315
Rob Landleyb73451d2006-02-24 16:29:00 +00001316 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1317 dkbasename, dkbasename, dkbasename);
1318 if (read_line()) {
1319 line_ptr[strlen(line_ptr)-1] = '\0';
1320 dkbasename = line_ptr;
1321 }
1322 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1323 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1324 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001325
Rob Landleyb73451d2006-02-24 16:29:00 +00001326/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1327 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1328 bcopy(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001329
Rob Landleyb73451d2006-02-24 16:29:00 +00001330/* The disklabel will be overwritten by 0's from bootxx anyway */
1331 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001332
Rob Landleyb73451d2006-02-24 16:29:00 +00001333 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1334 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001335 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001336 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001337
Rob Landleyb73451d2006-02-24 16:29:00 +00001338 e = d + sizeof(struct xbsd_disklabel);
1339 for (p = d; p < e; p++)
1340 if (*p) {
1341 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1342 exit(EXIT_FAILURE);
1343 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001344
Rob Landleyb73451d2006-02-24 16:29:00 +00001345 bcopy(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001346
1347#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001348 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001349#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001350 sector = 0;
1351 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001352#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001353 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001354#endif
1355
Rob Landleyb73451d2006-02-24 16:29:00 +00001356 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1357 fdisk_fatal(unable_to_seek);
1358 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1359 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001360
1361#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001362 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001363#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001364 printf(_("Bootstrap installed on %s.\n"),
1365 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001366#endif
1367
Rob Landleyb73451d2006-02-24 16:29:00 +00001368 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001369}
1370
1371static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001372xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373{
Rob Landleyb73451d2006-02-24 16:29:00 +00001374 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001375
Rob Landleyb73451d2006-02-24 16:29:00 +00001376 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1377 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001378}
1379
1380static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001381xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001382{
Rob Landleyb73451d2006-02-24 16:29:00 +00001383 char prompt[256];
1384 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001385
Rob Landleyb73451d2006-02-24 16:29:00 +00001386 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1387 do
1388 l = tolower(read_char(prompt));
1389 while (l < 'a' || l > 'a' + max - 1);
1390 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001391}
1392
1393static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001394xbsd_check_new_partition(int *i)
1395{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001396 /* room for more? various BSD flavours have different maxima */
1397 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1398 int t;
1399
1400 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1401 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1402 break;
1403
1404 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001405 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001406 "has been created\n"));
1407 return 0;
1408 }
1409 }
1410
1411 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1412
1413 if (*i >= xbsd_dlabel.d_npartitions)
1414 xbsd_dlabel.d_npartitions = (*i) + 1;
1415
1416 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001417 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001418 return 0;
1419 }
1420
1421 return 1;
1422}
1423
1424static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001425xbsd_list_types(void)
1426{
1427 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001428}
1429
1430static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001431xbsd_dkcksum(struct xbsd_disklabel *lp)
1432{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001433 u_short *start, *end;
1434 u_short sum = 0;
1435
1436 start = (u_short *) lp;
1437 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1438 while (start < end)
1439 sum ^= *start++;
1440 return sum;
1441}
1442
1443static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001444xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1445{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001446 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001447
Rob Landleyb73451d2006-02-24 16:29:00 +00001448 get_geometry();
1449 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001450
Rob Landleyb73451d2006-02-24 16:29:00 +00001451 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001452
Rob Landleyb73451d2006-02-24 16:29:00 +00001453 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1454 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001455 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001456 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001457
1458#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001459 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001460#endif
1461
1462#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001463 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001464#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001465 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001466#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001467 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1468 d->d_nsectors = sectors; /* sectors/track */
1469 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1470 d->d_ncylinders = cylinders;
1471 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1472 if (d->d_secpercyl == 0)
1473 d->d_secpercyl = 1; /* avoid segfaults */
1474 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001475
Rob Landleyb73451d2006-02-24 16:29:00 +00001476 d->d_rpm = 3600;
1477 d->d_interleave = 1;
1478 d->d_trackskew = 0;
1479 d->d_cylskew = 0;
1480 d->d_headswitch = 0;
1481 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001482
Rob Landleyb73451d2006-02-24 16:29:00 +00001483 d->d_magic2 = BSD_DISKMAGIC;
1484 d->d_bbsize = BSD_BBSIZE;
1485 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001486
1487#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001488 d->d_npartitions = 4;
1489 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001490 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001491 pp->p_offset = get_start_sect(p);
1492 pp->p_size = get_nr_sects(p);
1493 pp->p_fstype = BSD_FS_UNUSED;
1494 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001495 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001496 pp->p_offset = 0;
1497 pp->p_size = d->d_secperunit;
1498 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001499#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001500 d->d_npartitions = 3;
1501 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001502 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001503 pp->p_offset = 0;
1504 pp->p_size = d->d_secperunit;
1505 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001506#endif
1507
1508 return 1;
1509}
1510
1511/*
1512 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1513 * If it has the right magic, return 1.
1514 */
1515static int
1516xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1517{
1518 int t, sector;
1519
1520 /* p is used only to get the starting sector */
1521#if !defined (__alpha__)
1522 sector = (p ? get_start_sect(p) : 0);
1523#elif defined (__alpha__)
1524 sector = 0;
1525#endif
1526
Rob Landleyb73451d2006-02-24 16:29:00 +00001527 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1528 fdisk_fatal(unable_to_seek);
1529 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1530 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001531
Rob Landleyb73451d2006-02-24 16:29:00 +00001532 bcopy(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1533 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001534
Rob Landleyb73451d2006-02-24 16:29:00 +00001535 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001536 return 0;
1537
Rob Landleyb73451d2006-02-24 16:29:00 +00001538 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1539 d->d_partitions[t].p_size = 0;
1540 d->d_partitions[t].p_offset = 0;
1541 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001542 }
1543
Rob Landleyb73451d2006-02-24 16:29:00 +00001544 if (d->d_npartitions > BSD_MAXPARTITIONS)
1545 fprintf(stderr, _("Warning: too many partitions "
1546 "(%d, maximum is %d).\n"),
1547 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001548 return 1;
1549}
1550
1551static int
1552xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1553{
Rob Landleyb73451d2006-02-24 16:29:00 +00001554 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001555
1556#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001557 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001558#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001559 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001560#endif
1561
Rob Landleyb73451d2006-02-24 16:29:00 +00001562 d->d_checksum = 0;
1563 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001564
Rob Landleyb73451d2006-02-24 16:29:00 +00001565 /* This is necessary if we want to write the bootstrap later,
1566 otherwise we'd write the old disklabel with the bootstrap.
1567 */
1568 bcopy(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1569 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001570
1571#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001572 alpha_bootblock_checksum (disklabelbuffer);
1573 if (lseek(fd, 0, SEEK_SET) == -1)
1574 fdisk_fatal(unable_to_seek);
1575 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1576 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001577#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001578 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1579 fdisk_fatal(unable_to_seek);
1580 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1581 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001582#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001583 sync_disks();
1584 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001585}
1586
1587
1588#if !defined (__alpha__)
1589static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001590xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001591{
Rob Landleyb73451d2006-02-24 16:29:00 +00001592 switch (linux_type) {
1593 case 0x01: /* DOS 12-bit FAT */
1594 case 0x04: /* DOS 16-bit <32M */
1595 case 0x06: /* DOS 16-bit >=32M */
1596 case 0xe1: /* DOS access */
1597 case 0xe3: /* DOS R/O */
1598 case 0xf2: /* DOS secondary */
1599 return BSD_FS_MSDOS;
1600 case 0x07: /* OS/2 HPFS */
1601 return BSD_FS_HPFS;
1602 default:
1603 return BSD_FS_OTHER;
1604 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001605}
1606
1607static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001608xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001609{
Rob Landleyb73451d2006-02-24 16:29:00 +00001610 int k, i;
1611 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001612
Rob Landleyb73451d2006-02-24 16:29:00 +00001613 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001614
Rob Landleyb73451d2006-02-24 16:29:00 +00001615 if (!xbsd_check_new_partition(&i))
1616 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001617
Rob Landleyb73451d2006-02-24 16:29:00 +00001618 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001619
Rob Landleyb73451d2006-02-24 16:29:00 +00001620 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1621 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1622 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001623}
1624#endif
1625
1626#if defined (__alpha__)
1627
1628#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001629typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001630#endif
1631
1632static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001633alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001634{
Rob Landleyb73451d2006-02-24 16:29:00 +00001635 uint64_t *dp, sum;
1636 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001637
Rob Landleyb73451d2006-02-24 16:29:00 +00001638 dp = (uint64_t *)boot;
1639 sum = 0;
1640 for (i = 0; i < 63; i++)
1641 sum += dp[i];
1642 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001643}
1644#endif /* __alpha__ */
1645
1646#endif /* OSF_LABEL */
1647
1648#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1649static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001650__swap16(unsigned short x)
1651{
Eric Andersenacd244a2002-12-11 03:49:33 +00001652 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001653}
1654
Eric Andersenacd244a2002-12-11 03:49:33 +00001655static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001656__swap32(uint32_t x)
1657{
1658 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001659 ((x & 0xFF00) << 8) |
1660 ((x & 0xFF0000) >> 8) |
1661 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001662}
1663#endif
1664
1665#ifdef CONFIG_FEATURE_SGI_LABEL
1666/*
1667 *
1668 * fdisksgilabel.c
1669 *
1670 * Copyright (C) Andreas Neuper, Sep 1998.
1671 * This file may be modified and redistributed under
1672 * the terms of the GNU Public License.
1673 *
1674 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1675 * Internationalization
1676 */
1677
1678
Rob Landleyb73451d2006-02-24 16:29:00 +00001679static int sgi_other_endian;
1680static int debug;
1681static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001682
1683/*
1684 * only dealing with free blocks here
1685 */
1686
Rob Landleyb73451d2006-02-24 16:29:00 +00001687typedef struct {
1688 unsigned int first;
1689 unsigned int last;
1690} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001691static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1692
1693static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001694setfreelist(int i, unsigned int f, unsigned int l)
1695{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001696 freelist[i].first = f;
1697 freelist[i].last = l;
1698}
1699
1700static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001701add2freelist(unsigned int f, unsigned int l)
1702{
1703 int i;
1704 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001705 if (freelist[i].last == 0)
1706 break;
1707 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001708}
1709
1710static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001711clearfreelist(void)
1712{
Eric Andersen040f4402003-07-30 08:40:37 +00001713 int i;
1714
1715 for (i = 0; i < 17 ; i++)
1716 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001717}
1718
Eric Andersen040f4402003-07-30 08:40:37 +00001719static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001720isinfreelist(unsigned int b)
1721{
Eric Andersen040f4402003-07-30 08:40:37 +00001722 int i;
1723
1724 for (i = 0; i < 17 ; i++)
1725 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001726 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001727 return 0;
1728}
1729 /* return last vacant block of this stride (never 0). */
1730 /* the '>=' is not quite correct, but simplifies the code */
1731/*
1732 * end of free blocks section
1733 */
1734
1735static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001736/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1737/* 0x01 */ { "\x01" "SGI trkrepl" },
1738/* 0x02 */ { "\x02" "SGI secrepl" },
1739/* SGI_SWAP */ { "\x03" "SGI raw" },
1740/* 0x04 */ { "\x04" "SGI bsd" },
1741/* 0x05 */ { "\x05" "SGI sysv" },
1742/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1743/* SGI_EFS */ { "\x07" "SGI efs" },
1744/* 0x08 */ { "\x08" "SGI lvol" },
1745/* 0x09 */ { "\x09" "SGI rlvol" },
1746/* SGI_XFS */ { "\x0a" "SGI xfs" },
1747/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1748/* SGI_XLV */ { "\x0c" "SGI xlv" },
1749/* SGI_XVM */ { "\x0d" "SGI xvm" },
1750/* LINUX_SWAP */ { "\x82" "Linux swap" },
1751/* LINUX_NATIVE */ { "\x83" "Linux native" },
1752/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1753/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1754 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001755};
1756
1757
1758static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001759sgi_get_nsect(void)
1760{
1761 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001762}
1763
1764static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001765sgi_get_ntrks(void)
1766{
1767 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001768}
1769
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001770static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001771two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1772{
1773 int i = 0;
1774 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001775
Rob Landleyb73451d2006-02-24 16:29:00 +00001776 size /= sizeof(unsigned int);
1777 for (i = 0; i < size; i++)
1778 sum -= SGI_SSWAP32(base[i]);
1779 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001780}
1781
1782static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001783check_sgi_label(void)
1784{
1785 if (sizeof(sgilabel) > 512) {
1786 fprintf(stderr,
1787 _("According to MIPS Computer Systems, Inc the "
1788 "Label must not contain more than 512 bytes\n"));
1789 exit(1);
1790 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001791
Rob Landleyb73451d2006-02-24 16:29:00 +00001792 if (sgilabel->magic != SGI_LABEL_MAGIC
1793 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00001794 current_label_type = label_dos;
Rob Landleyb73451d2006-02-24 16:29:00 +00001795 return 0;
1796 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001797
Rob Landleyb73451d2006-02-24 16:29:00 +00001798 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1799 /*
1800 * test for correct checksum
1801 */
1802 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1803 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001804 fprintf(stderr,
1805 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001806 }
1807 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00001808 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00001809 partitions = 16;
1810 sgi_volumes = 15;
1811 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001812}
1813
Eric Andersen040f4402003-07-30 08:40:37 +00001814static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001815sgi_get_start_sector(int i)
1816{
1817 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001818}
1819
Eric Andersen040f4402003-07-30 08:40:37 +00001820static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001821sgi_get_num_sectors(int i)
1822{
1823 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001824}
1825
1826static int
Eric Andersen040f4402003-07-30 08:40:37 +00001827sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001828{
Rob Landleyb73451d2006-02-24 16:29:00 +00001829 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001830}
1831
1832static int
1833sgi_get_bootpartition(void)
1834{
Rob Landleyb73451d2006-02-24 16:29:00 +00001835 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001836}
1837
1838static int
1839sgi_get_swappartition(void)
1840{
Rob Landleyb73451d2006-02-24 16:29:00 +00001841 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001842}
1843
1844static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001845sgi_list_table(int xtra)
1846{
1847 int i, w, wd;
1848 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001849
Rob Landleyb73451d2006-02-24 16:29:00 +00001850 if(xtra) {
1851 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1852 "%d cylinders, %d physical cylinders\n"
1853 "%d extra sects/cyl, interleave %d:1\n"
1854 "%s\n"
1855 "Units = %s of %d * 512 bytes\n\n"),
1856 disk_device, heads, sectors, cylinders,
1857 SGI_SSWAP16(sgiparam.pcylcount),
1858 SGI_SSWAP16(sgiparam.sparecyl),
1859 SGI_SSWAP16(sgiparam.ilfact),
1860 (char *)sgilabel,
1861 str_units(PLURAL), units_per_sector);
1862 } else {
1863 printf( _("\nDisk %s (SGI disk label): "
1864 "%d heads, %d sectors, %d cylinders\n"
1865 "Units = %s of %d * 512 bytes\n\n"),
1866 disk_device, heads, sectors, cylinders,
1867 str_units(PLURAL), units_per_sector );
1868 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001869
Rob Landleyb73451d2006-02-24 16:29:00 +00001870 w = strlen(disk_device);
1871 wd = strlen(_("Device"));
1872 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001873 w = wd;
1874
Rob Landleyb73451d2006-02-24 16:29:00 +00001875 printf(_("----- partitions -----\n"
1876 "Pt# %*s Info Start End Sectors Id System\n"),
1877 w + 2, _("Device"));
1878 for (i = 0 ; i < partitions; i++) {
1879 if( sgi_get_num_sectors(i) || debug ) {
1880 uint32_t start = sgi_get_start_sector(i);
1881 uint32_t len = sgi_get_num_sectors(i);
1882 kpi++; /* only count nonempty partitions */
1883 printf(
1884 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1885/* fdisk part number */ i+1,
1886/* device */ partname(disk_device, kpi, w+3),
1887/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1888/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1889/* start */ (long) scround(start),
1890/* end */ (long) scround(start+len)-1,
1891/* no odd flag on end */(long) len,
1892/* type id */ sgi_get_sysid(i),
1893/* type name */ partition_type(sgi_get_sysid(i)));
1894 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001895 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001896 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1897 "----- Directory Entries -----\n"),
1898 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001899 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001900 if (sgilabel->directory[i].vol_file_size) {
1901 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1902 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1903 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001904
Rob Landleyb73451d2006-02-24 16:29:00 +00001905 printf(_("%2d: %-10s sector%5u size%8u\n"),
1906 i, (char*)name, (unsigned int) start, (unsigned int) len);
1907 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001908 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001909}
1910
1911static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001912sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001913{
Rob Landleyb73451d2006-02-24 16:29:00 +00001914 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001915}
1916
Eric Andersen040f4402003-07-30 08:40:37 +00001917static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001918sgi_get_lastblock(void)
1919{
1920 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001921}
1922
1923static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001924sgi_set_swappartition(int i)
1925{
1926 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001927}
1928
1929static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001930sgi_check_bootfile(const char* aFile)
1931{
1932 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1933 printf(_("\nInvalid Bootfile!\n"
1934 "\tThe bootfile must be an absolute non-zero pathname,\n"
1935 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1936 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001937 } else {
1938 if (strlen(aFile) > 16) {
1939 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001940 "16 bytes maximum.\n"));
1941 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001942 } else {
1943 if (aFile[0] != '/') {
1944 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001945 "fully qualified pathname.\n"));
1946 return 0;
1947 }
Eric Andersen040f4402003-07-30 08:40:37 +00001948 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001949 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001950 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001951 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1952 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001953 /* filename is correct and did change */
1954 return 1;
1955 }
1956 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001957}
1958
1959static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001960sgi_get_bootfile(void)
1961{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001962 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001963}
1964
1965static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001966sgi_set_bootfile(const char* aFile)
1967{
1968 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001969
Rob Landleyb73451d2006-02-24 16:29:00 +00001970 if (sgi_check_bootfile(aFile)) {
1971 while (i < 16) {
1972 if ((aFile[i] != '\n') /* in principle caught again by next line */
1973 && (strlen(aFile) > i))
1974 sgilabel->boot_file[i] = aFile[i];
1975 else
1976 sgilabel->boot_file[i] = 0;
1977 i++;
1978 }
1979 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001980 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001981}
1982
1983static void
1984create_sgiinfo(void)
1985{
Rob Landleyb73451d2006-02-24 16:29:00 +00001986 /* I keep SGI's habit to write the sgilabel to the second block */
1987 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1988 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1989 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001990}
1991
Eric Andersen040f4402003-07-30 08:40:37 +00001992static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001993
1994static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001995sgi_write_table(void)
1996{
1997 sgilabel->csum = 0;
1998 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
1999 (unsigned int*)sgilabel, sizeof(*sgilabel)));
2000 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00002001 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00002002
2003 if (lseek(fd, 0, SEEK_SET) < 0)
2004 fdisk_fatal(unable_to_seek);
2005 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
2006 fdisk_fatal(unable_to_write);
2007 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2008 /*
2009 * keep this habit of first writing the "sgilabel".
2010 * I never tested whether it works without (AN 981002).
2011 */
2012 sgiinfo *info = fill_sgiinfo();
2013 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2014 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2015 fdisk_fatal(unable_to_seek);
2016 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2017 fdisk_fatal(unable_to_write);
2018 free(info);
2019 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002020}
2021
2022static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002023compare_start(int *x, int *y)
2024{
2025 /*
2026 * sort according to start sectors
2027 * and prefers largest partition:
2028 * entry zero is entire disk entry
2029 */
2030 unsigned int i = *x;
2031 unsigned int j = *y;
2032 unsigned int a = sgi_get_start_sector(i);
2033 unsigned int b = sgi_get_start_sector(j);
2034 unsigned int c = sgi_get_num_sectors(i);
2035 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002036
Rob Landleyb73451d2006-02-24 16:29:00 +00002037 if (a == b)
2038 return (d > c) ? 1 : (d == c) ? 0 : -1;
2039 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002040}
2041
2042
2043static int
Eric Andersen040f4402003-07-30 08:40:37 +00002044verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002045{
Rob Landleyb73451d2006-02-24 16:29:00 +00002046 int Index[16]; /* list of valid partitions */
2047 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2048 int entire = 0, i = 0;
2049 unsigned int start = 0;
2050 long long gap = 0; /* count unused blocks */
2051 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002052
Rob Landleyb73451d2006-02-24 16:29:00 +00002053 clearfreelist();
2054 for (i = 0; i < 16; i++) {
2055 if (sgi_get_num_sectors(i) != 0) {
2056 Index[sortcount++] = i;
2057 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2058 if (entire++ == 1) {
2059 if (verbose)
2060 printf(_("More than one entire disk entry present.\n"));
2061 }
2062 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002063 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002064 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002065 if (sortcount == 0) {
2066 if (verbose)
2067 printf(_("No partitions defined\n"));
2068 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2069 }
2070 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2071 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2072 if ((Index[0] != 10) && verbose)
2073 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2074 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2075 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002076 "at block 0,\n"
2077 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002078 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002079 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002080 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2081 printf(_("The entire disk partition is only %d diskblock large,\n"
2082 "but the disk is %d diskblocks long.\n"),
2083 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002084 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002085 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002086 if (verbose)
2087 printf(_("One Partition (#11) should cover the entire disk.\n"));
2088 if (debug > 2)
2089 printf("sysid=%d\tpartition=%d\n",
2090 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002091 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002092 for (i = 1, start = 0; i < sortcount; i++) {
2093 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2094
2095 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2096 if (debug) /* I do not understand how some disks fulfil it */
2097 if (verbose)
2098 printf(_("Partition %d does not start on cylinder boundary.\n"),
2099 Index[i]+1);
2100 }
2101 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2102 if (debug) /* I do not understand how some disks fulfil it */
2103 if (verbose)
2104 printf(_("Partition %d does not end on cylinder boundary.\n"),
2105 Index[i]+1);
2106 }
2107 /* We cannot handle several "entire disk" entries. */
2108 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2109 if (start > sgi_get_start_sector(Index[i])) {
2110 if (verbose)
2111 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2112 Index[i-1]+1, Index[i]+1,
2113 start - sgi_get_start_sector(Index[i]));
2114 if (gap > 0) gap = -gap;
2115 if (gap == 0) gap = -1;
2116 }
2117 if (start < sgi_get_start_sector(Index[i])) {
2118 if (verbose)
2119 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2120 sgi_get_start_sector(Index[i]) - start,
2121 start, sgi_get_start_sector(Index[i])-1);
2122 gap += sgi_get_start_sector(Index[i]) - start;
2123 add2freelist(start, sgi_get_start_sector(Index[i]));
2124 }
2125 start = sgi_get_start_sector(Index[i])
2126 + sgi_get_num_sectors(Index[i]);
2127 if (debug > 1) {
2128 if (verbose)
2129 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2130 sgi_get_start_sector(Index[i]),
2131 sgi_get_num_sectors(Index[i]),
2132 sgi_get_sysid(Index[i]));
2133 }
2134 }
2135 if (start < lastblock) {
2136 if (verbose)
2137 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2138 lastblock - start, start, lastblock-1);
2139 gap += lastblock - start;
2140 add2freelist(start, lastblock);
2141 }
2142 /*
2143 * Done with arithmetics
2144 * Go for details now
2145 */
2146 if (verbose) {
2147 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2148 printf(_("\nThe boot partition does not exist.\n"));
2149 }
2150 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2151 printf(_("\nThe swap partition does not exist.\n"));
2152 } else {
2153 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2154 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2155 printf(_("\nThe swap partition has no swap type.\n"));
2156 }
2157 if (sgi_check_bootfile("/unix"))
2158 printf(_("\tYou have chosen an unusual boot file name.\n"));
2159 }
2160 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002161}
2162
2163static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002164sgi_gaps(void)
2165{
2166 /*
2167 * returned value is:
2168 * = 0 : disk is properly filled to the rim
2169 * < 0 : there is an overlap
2170 * > 0 : there is still some vacant space
2171 */
2172 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002173}
2174
2175static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002176sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002177{
Rob Landleyb73451d2006-02-24 16:29:00 +00002178 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2179 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2180 return;
2181 }
2182 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2183 && (sgi_get_start_sector(i) < 1) ) {
2184 read_chars(
2185 _("It is highly recommended that the partition at offset 0\n"
2186 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2187 "retrieve from its directory standalone tools like sash and fx.\n"
2188 "Only the \"SGI volume\" entire disk section may violate this.\n"
2189 "Type YES if you are sure about tagging this partition differently.\n"));
2190 if (strcmp(line_ptr, _("YES\n")))
2191 return;
2192 }
2193 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002194}
2195
2196/* returns partition index of first entry marked as entire disk */
2197static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002198sgi_entire(void)
2199{
2200 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002201
Rob Landleyb73451d2006-02-24 16:29:00 +00002202 for (i = 0; i < 16; i++)
2203 if (sgi_get_sysid(i) == SGI_VOLUME)
2204 return i;
2205 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002206}
2207
2208static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002209sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2210{
2211 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2212 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2213 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2214 set_changed(i);
2215 if (sgi_gaps() < 0) /* rebuild freelist */
2216 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002217}
2218
2219static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002220sgi_set_entire(void)
2221{
2222 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002223
Rob Landleyb73451d2006-02-24 16:29:00 +00002224 for (n = 10; n < partitions; n++) {
2225 if(!sgi_get_num_sectors(n) ) {
2226 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2227 break;
2228 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002229 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002230}
2231
2232static void
2233sgi_set_volhdr(void)
2234{
Rob Landleyb73451d2006-02-24 16:29:00 +00002235 int n;
2236
2237 for (n = 8; n < partitions; n++) {
2238 if (!sgi_get_num_sectors(n)) {
2239 /*
2240 * 5 cylinders is an arbitrary value I like
2241 * IRIX 5.3 stored files in the volume header
2242 * (like sash, symmon, fx, ide) with ca. 3200
2243 * sectors.
2244 */
2245 if (heads * sectors * 5 < sgi_get_lastblock())
2246 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2247 break;
2248 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002249 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002250}
2251
2252static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002253sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002254{
Rob Landleyb73451d2006-02-24 16:29:00 +00002255 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002256}
2257
2258static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002259sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002260{
Rob Landleyb73451d2006-02-24 16:29:00 +00002261 char mesg[256];
2262 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002263
Rob Landleyb73451d2006-02-24 16:29:00 +00002264 if (n == 10) {
2265 sys = SGI_VOLUME;
2266 } else if (n == 8) {
2267 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002268 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002269 if(sgi_get_num_sectors(n)) {
2270 printf(_("Partition %d is already defined. Delete "
2271 "it before re-adding it.\n"), n + 1);
2272 return;
2273 }
2274 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2275 printf(_("Attempting to generate entire disk entry automatically.\n"));
2276 sgi_set_entire();
2277 sgi_set_volhdr();
2278 }
2279 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2280 printf(_("The entire disk is already covered with partitions.\n"));
2281 return;
2282 }
2283 if (sgi_gaps() < 0) {
2284 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2285 return;
2286 }
2287 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2288 while (1) {
2289 if(sys == SGI_VOLUME) {
2290 last = sgi_get_lastblock();
2291 first = read_int(0, 0, last-1, 0, mesg);
2292 if (first != 0) {
2293 printf(_("It is highly recommended that eleventh partition\n"
2294 "covers the entire disk and is of type `SGI volume'\n"));
2295 }
2296 } else {
2297 first = freelist[0].first;
2298 last = freelist[0].last;
2299 first = read_int(scround(first), scround(first), scround(last)-1,
2300 0, mesg);
2301 }
2302 if (display_in_cyl_units)
2303 first *= units_per_sector;
2304 else
2305 first = first; /* align to cylinder if you know how ... */
2306 if(!last )
2307 last = isinfreelist(first);
2308 if(last == 0) {
2309 printf(_("You will get a partition overlap on the disk. "
2310 "Fix it first!\n"));
2311 } else
2312 break;
2313 }
2314 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2315 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2316 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002317 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002318 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002319 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002320 last = last; /* align to cylinder if You know how ... */
2321 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2322 printf(_("It is highly recommended that eleventh partition\n"
2323 "covers the entire disk and is of type `SGI volume'\n"));
2324 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002325}
2326
Eric Andersen040f4402003-07-30 08:40:37 +00002327#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002328static void
2329create_sgilabel(void)
2330{
Rob Landleyb73451d2006-02-24 16:29:00 +00002331 struct hd_geometry geometry;
2332 struct {
2333 unsigned int start;
2334 unsigned int nsect;
2335 int sysid;
2336 } old[4];
2337 int i = 0;
2338 long longsectors; /* the number of sectors on the device */
2339 int res; /* the result from the ioctl */
2340 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002341
Rob Landleyb73451d2006-02-24 16:29:00 +00002342 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002343
Rob Landleyb73451d2006-02-24 16:29:00 +00002344 fprintf( stderr,
2345 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2346 "until you decide to write them. After that, of course, the previous\n"
2347 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002348
Rob Landleyb73451d2006-02-24 16:29:00 +00002349 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
2350 res = ioctl(fd, BLKGETSIZE, &longsectors);
2351 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2352 heads = geometry.heads;
2353 sectors = geometry.sectors;
2354 if (res == 0) {
2355 /* the get device size ioctl was successful */
2356 cylinders = longsectors / (heads * sectors);
2357 cylinders /= sec_fac;
2358 } else {
2359 /* otherwise print error and use truncated version */
2360 cylinders = geometry.cylinders;
2361 fprintf(stderr,
2362 _("Warning: BLKGETSIZE ioctl failed on %s. "
2363 "Using geometry cylinder value of %d.\n"
2364 "This value may be truncated for devices"
2365 " > 33.8 GB.\n"), disk_device, cylinders);
2366 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002367 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002368 for (i = 0; i < 4; i++) {
2369 old[i].sysid = 0;
2370 if (valid_part_table_flag(MBRbuffer)) {
2371 if(get_part_table(i)->sys_ind) {
2372 old[i].sysid = get_part_table(i)->sys_ind;
2373 old[i].start = get_start_sect(get_part_table(i));
2374 old[i].nsect = get_nr_sects(get_part_table(i));
2375 printf(_("Trying to keep parameters of partition %d.\n"), i);
2376 if (debug)
2377 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2378 old[i].sysid, old[i].start, old[i].nsect);
2379 }
2380 }
2381 }
Eric Andersen040f4402003-07-30 08:40:37 +00002382
Rob Landleyb73451d2006-02-24 16:29:00 +00002383 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2384 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2385 sgilabel->boot_part = SGI_SSWAP16(0);
2386 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002387
Rob Landleyb73451d2006-02-24 16:29:00 +00002388 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2389 memset(sgilabel->boot_file, 0, 16);
2390 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002391
Rob Landleyb73451d2006-02-24 16:29:00 +00002392 sgilabel->devparam.skew = (0);
2393 sgilabel->devparam.gap1 = (0);
2394 sgilabel->devparam.gap2 = (0);
2395 sgilabel->devparam.sparecyl = (0);
2396 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2397 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2398 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002399 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002400 sgilabel->devparam.cmd_tag_queue_depth = (0);
2401 sgilabel->devparam.unused0 = (0);
2402 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2403 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002404 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002405 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2406 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2407 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002408 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002409 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2410 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2411 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2412 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2413 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2414 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2415 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2416 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2417 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2418 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2419 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
Rob Landley5527b912006-02-25 03:46:10 +00002420 current_label_type = label_sgi;
Rob Landleyb73451d2006-02-24 16:29:00 +00002421 partitions = 16;
2422 sgi_volumes = 15;
2423 sgi_set_entire();
2424 sgi_set_volhdr();
2425 for (i = 0; i < 4; i++) {
2426 if(old[i].sysid) {
2427 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2428 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002429 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002430}
2431
2432static void
2433sgi_set_xcyl(void)
2434{
Rob Landleyb73451d2006-02-24 16:29:00 +00002435 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002436}
Eric Andersen040f4402003-07-30 08:40:37 +00002437#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002438
2439/* _____________________________________________________________
2440 */
2441
Eric Andersen040f4402003-07-30 08:40:37 +00002442static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002443fill_sgiinfo(void)
2444{
Rob Landleyb73451d2006-02-24 16:29:00 +00002445 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002446
Rob Landleyb73451d2006-02-24 16:29:00 +00002447 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2448 info->b1 = SGI_SSWAP32(-1);
2449 info->b2 = SGI_SSWAP16(-1);
2450 info->b3 = SGI_SSWAP16(1);
2451 /* You may want to replace this string !!!!!!! */
2452 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2453 strcpy( (char*)info->serial, "0000" );
2454 info->check1816 = SGI_SSWAP16(18*256 +16 );
2455 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2456 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002457}
2458#endif /* SGI_LABEL */
2459
2460
2461#ifdef CONFIG_FEATURE_SUN_LABEL
2462/*
2463 * fdisksunlabel.c
2464 *
2465 * I think this is mostly, or entirely, due to
2466 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2467 *
2468 * Merged with fdisk for other architectures, aeb, June 1998.
2469 *
2470 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2471 * Internationalization
2472 */
2473
2474
Rob Landleyb73451d2006-02-24 16:29:00 +00002475static int sun_other_endian;
2476static int scsi_disk;
2477static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002478
2479#ifndef IDE0_MAJOR
2480#define IDE0_MAJOR 3
2481#endif
2482#ifndef IDE1_MAJOR
2483#define IDE1_MAJOR 22
2484#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002485
Rob Landleyb73451d2006-02-24 16:29:00 +00002486static void
2487guess_device_type(void)
2488{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002489 struct stat bootstat;
2490
Rob Landleyb73451d2006-02-24 16:29:00 +00002491 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002492 scsi_disk = 0;
2493 floppy = 0;
2494 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002495 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2496 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002497 scsi_disk = 0;
2498 floppy = 0;
2499 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002500 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002501 scsi_disk = 0;
2502 floppy = 1;
2503 } else {
2504 scsi_disk = 1;
2505 floppy = 0;
2506 }
2507}
2508
2509static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002510 { "\x00" "Empty" }, /* 0 */
2511 { "\x01" "Boot" }, /* 1 */
2512 { "\x02" "SunOS root" }, /* 2 */
2513 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2514 { "\x04" "SunOS usr" }, /* 4 */
2515 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2516 { "\x06" "SunOS stand" }, /* 6 */
2517 { "\x07" "SunOS var" }, /* 7 */
2518 { "\x08" "SunOS home" }, /* 8 */
2519 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2520 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2521 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002522/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002523 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2524 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002525};
2526
2527
2528static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002529set_sun_partition(int i, uint start, uint stop, int sysid)
2530{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002531 sunlabel->infos[i].id = sysid;
2532 sunlabel->partitions[i].start_cylinder =
2533 SUN_SSWAP32(start / (heads * sectors));
2534 sunlabel->partitions[i].num_sectors =
2535 SUN_SSWAP32(stop - start);
2536 set_changed(i);
2537}
2538
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002539static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002540check_sun_label(void)
2541{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002542 unsigned short *ush;
2543 int csum;
2544
Rob Landleyb73451d2006-02-24 16:29:00 +00002545 if (sunlabel->magic != SUN_LABEL_MAGIC
2546 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Rob Landley5527b912006-02-25 03:46:10 +00002547 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002548 sun_other_endian = 0;
2549 return 0;
2550 }
2551 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2552 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2553 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2554 if (csum) {
2555 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2556 "Probably you'll have to set all the values,\n"
2557 "e.g. heads, sectors, cylinders and partitions\n"
2558 "or force a fresh label (s command in main menu)\n"));
2559 } else {
2560 heads = SUN_SSWAP16(sunlabel->ntrks);
2561 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2562 sectors = SUN_SSWAP16(sunlabel->nsect);
2563 }
2564 update_units();
Rob Landley5527b912006-02-25 03:46:10 +00002565 current_label_type = label_sun;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002566 partitions = 8;
2567 return 1;
2568}
2569
2570static const struct sun_predefined_drives {
2571 const char *vendor;
2572 const char *model;
2573 unsigned short sparecyl;
2574 unsigned short ncyl;
2575 unsigned short nacyl;
2576 unsigned short pcylcount;
2577 unsigned short ntrks;
2578 unsigned short nsect;
2579 unsigned short rspeed;
2580} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002581 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2582 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2583 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2584 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2585 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2586 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2587 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2588 { "","SUN0104",1,974,2,1019,6,35,3662},
2589 { "","SUN0207",4,1254,2,1272,9,36,3600},
2590 { "","SUN0327",3,1545,2,1549,9,46,3600},
2591 { "","SUN0340",0,1538,2,1544,6,72,4200},
2592 { "","SUN0424",2,1151,2,2500,9,80,4400},
2593 { "","SUN0535",0,1866,2,2500,7,80,5400},
2594 { "","SUN0669",5,1614,2,1632,15,54,3600},
2595 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2596 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2597 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2598 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2599 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002600};
2601
2602static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002603sun_autoconfigure_scsi(void)
2604{
2605 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002606
2607#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002608 unsigned int id[2];
2609 char buffer[2048];
2610 char buffer2[2048];
2611 FILE *pfd;
2612 char *vendor;
2613 char *model;
2614 char *q;
2615 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002616
Rob Landleyb73451d2006-02-24 16:29:00 +00002617 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2618 sprintf(buffer,
2619 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002620#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002621 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002622#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002623 /* This is very wrong (works only if you have one HBA),
2624 but I haven't found a way how to get hostno
2625 from the current kernel */
2626 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002627#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002628 (id[0]>>16) & 0xff,
2629 id[0] & 0xff,
2630 (id[0]>>8) & 0xff
2631 );
2632 pfd = fopen("/proc/scsi/scsi","r");
2633 if (pfd) {
2634 while (fgets(buffer2, 2048, pfd)) {
2635 if (!strcmp(buffer, buffer2)) {
2636 if (fgets(buffer2,2048,pfd)) {
2637 q = strstr(buffer2,"Vendor: ");
2638 if (q) {
2639 q += 8;
2640 vendor = q;
2641 q = strstr(q," ");
2642 *q++ = 0; /* truncate vendor name */
2643 q = strstr(q,"Model: ");
2644 if (q) {
2645 *q = 0;
2646 q += 7;
2647 model = q;
2648 q = strstr(q," Rev: ");
2649 if (q) {
2650 *q = 0;
2651 for (i = 0; i < SIZE(sun_drives); i++) {
2652 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2653 continue;
2654 if (!strstr(model, sun_drives[i].model))
2655 continue;
2656 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2657 p = sun_drives + i;
2658 break;
2659 }
2660 }
2661 }
2662 }
2663 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002664 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002665 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002666 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002667 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002668 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002669 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002670#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002671 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002672}
2673
Rob Landleyb73451d2006-02-24 16:29:00 +00002674static void
2675create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002676{
2677 struct hd_geometry geometry;
2678 unsigned int ndiv;
2679 int i;
2680 unsigned char c;
2681 const struct sun_predefined_drives *p = NULL;
2682
2683 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002684 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2685 "until you decide to write them. After that, of course, the previous\n"
2686 "content won't be recoverable.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002687#if BYTE_ORDER == LITTLE_ENDIAN
2688 sun_other_endian = 1;
2689#else
2690 sun_other_endian = 0;
2691#endif
2692 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2693 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2694 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002695 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002696 " ? auto configure\n"
2697 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002698 for (i = 0; i < SIZE(sun_drives); i++) {
2699 printf(" %c %s%s%s\n",
2700 i + 'a', sun_drives[i].vendor,
2701 (*sun_drives[i].vendor) ? " " : "",
2702 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002703 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002704 while (1) {
2705 c = read_char(_("Select type (? for auto, 0 for custom): "));
2706 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2707 p = sun_drives + c - 'a';
2708 break;
2709 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2710 p = sun_drives + c - 'A';
2711 break;
2712 } else if (c == '0') {
2713 break;
2714 } else if (c == '?' && scsi_disk) {
2715 p = sun_autoconfigure_scsi();
2716 if (!p)
2717 printf(_("Autoconfigure failed.\n"));
2718 else
2719 break;
2720 }
2721 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002722 }
2723 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002724 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2725 heads = geometry.heads;
2726 sectors = geometry.sectors;
2727 cylinders = geometry.cylinders;
2728 } else {
2729 heads = 0;
2730 sectors = 0;
2731 cylinders = 0;
2732 }
2733 if (floppy) {
2734 sunlabel->nacyl = 0;
2735 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2736 sunlabel->rspeed = SUN_SSWAP16(300);
2737 sunlabel->ilfact = SUN_SSWAP16(1);
2738 sunlabel->sparecyl = 0;
2739 } else {
2740 heads = read_int(1,heads,1024,0,_("Heads"));
2741 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002742 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002743 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002744 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002745 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2746 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2747 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2748 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2749 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2750 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2751 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002752 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002753 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2754 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2755 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2756 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2757 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2758 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2759 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2760 sunlabel->ilfact = SUN_SSWAP16(1);
2761 cylinders = p->ncyl;
2762 heads = p->ntrks;
2763 sectors = p->nsect;
2764 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002765 }
2766
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002767 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002768 "%s%s%s cyl %d alt %d hd %d sec %d",
2769 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2770 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002771 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2772
2773 sunlabel->ntrks = SUN_SSWAP16(heads);
2774 sunlabel->nsect = SUN_SSWAP16(sectors);
2775 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2776 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002777 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002778 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002779 if (cylinders * heads * sectors >= 150 * 2048) {
2780 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2781 } else
2782 ndiv = cylinders * 2 / 3;
2783 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2784 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2785 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002786 }
2787 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2788 {
2789 unsigned short *ush = (unsigned short *)sunlabel;
2790 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002791 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002792 csum ^= *ush++;
2793 sunlabel->csum = csum;
2794 }
2795
2796 set_all_unchanged();
2797 set_changed(0);
2798 get_boot(create_empty_sun);
2799}
2800
2801static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002802toggle_sunflags(int i, unsigned char mask)
2803{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002804 if (sunlabel->infos[i].flags & mask)
2805 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002806 else
2807 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002808 set_changed(i);
2809}
2810
2811static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002812fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2813{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002814 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002815
2816 *start = 0;
2817 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002818 for (i = 0; i < partitions; i++) {
2819 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002820 && sunlabel->infos[i].id
2821 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002822 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2823 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2824 if (continuous) {
2825 if (starts[i] == *start)
2826 *start += lens[i];
2827 else if (starts[i] + lens[i] >= *stop)
2828 *stop = starts[i];
2829 else
2830 continuous = 0;
2831 /* There will be probably more gaps
2832 than one, so lets check afterwards */
2833 }
2834 } else {
2835 starts[i] = 0;
2836 lens[i] = 0;
2837 }
2838 }
2839}
2840
2841static uint *verify_sun_starts;
2842
2843static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002844verify_sun_cmp(int *a, int *b)
2845{
2846 if (*a == -1) return 1;
2847 if (*b == -1) return -1;
2848 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2849 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002850}
2851
2852static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002853verify_sun(void)
2854{
2855 uint starts[8], lens[8], start, stop;
2856 int i,j,k,starto,endo;
2857 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002858
Rob Landleyb73451d2006-02-24 16:29:00 +00002859 verify_sun_starts = starts;
2860 fetch_sun(starts,lens,&start,&stop);
2861 for (k = 0; k < 7; k++) {
2862 for (i = 0; i < 8; i++) {
2863 if (k && (lens[i] % (heads * sectors))) {
2864 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002865 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002866 if (lens[i]) {
2867 for (j = 0; j < i; j++)
2868 if (lens[j]) {
2869 if (starts[j] == starts[i]+lens[i]) {
2870 starts[j] = starts[i]; lens[j] += lens[i];
2871 lens[i] = 0;
2872 } else if (starts[i] == starts[j]+lens[j]){
2873 lens[j] += lens[i];
2874 lens[i] = 0;
2875 } else if (!k) {
2876 if (starts[i] < starts[j]+lens[j]
2877 && starts[j] < starts[i]+lens[i]) {
2878 starto = starts[i];
2879 if (starts[j] > starto)
2880 starto = starts[j];
2881 endo = starts[i]+lens[i];
2882 if (starts[j]+lens[j] < endo)
2883 endo = starts[j]+lens[j];
2884 printf(_("Partition %d overlaps with others in "
2885 "sectors %d-%d\n"), i+1, starto, endo);
2886 }
2887 }
2888 }
2889 }
2890 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002891 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002892 for (i = 0; i < 8; i++) {
2893 if (lens[i])
2894 array[i] = i;
2895 else
2896 array[i] = -1;
2897 }
2898 qsort(array,SIZE(array),sizeof(array[0]),
2899 (int (*)(const void *,const void *)) verify_sun_cmp);
2900 if (array[0] == -1) {
2901 printf(_("No partitions defined\n"));
2902 return;
2903 }
2904 stop = cylinders * heads * sectors;
2905 if (starts[array[0]])
2906 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2907 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2908 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2909 }
2910 start = starts[array[i]] + lens[array[i]];
2911 if (start < stop)
2912 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002913}
2914
2915static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002916add_sun_partition(int n, int sys)
2917{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002918 uint start, stop, stop2;
2919 uint starts[8], lens[8];
2920 int whole_disk = 0;
2921
2922 char mesg[256];
2923 int i, first, last;
2924
2925 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2926 printf(_("Partition %d is already defined. Delete "
2927 "it before re-adding it.\n"), n + 1);
2928 return;
2929 }
2930
2931 fetch_sun(starts,lens,&start,&stop);
2932 if (stop <= start) {
2933 if (n == 2)
2934 whole_disk = 1;
2935 else {
2936 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002937 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002938 return;
2939 }
2940 }
2941 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002942 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002943 if (whole_disk)
2944 first = read_int(0, 0, 0, 0, mesg);
2945 else
2946 first = read_int(scround(start), scround(stop)+1,
2947 scround(stop), 0, mesg);
2948 if (display_in_cyl_units)
2949 first *= units_per_sector;
2950 else
2951 /* Starting sector has to be properly aligned */
2952 first = (first + heads * sectors - 1) / (heads * sectors);
2953 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002954 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002955It is highly recommended that the third partition covers the whole disk\n\
2956and is of type `Whole disk'\n");
2957 /* ewt asks to add: "don't start a partition at cyl 0"
2958 However, edmundo@rano.demon.co.uk writes:
2959 "In addition to having a Sun partition table, to be able to
2960 boot from the disc, the first partition, /dev/sdX1, must
2961 start at cylinder 0. This means that /dev/sdX1 contains
2962 the partition table and the boot block, as these are the
2963 first two sectors of the disc. Therefore you must be
2964 careful what you use /dev/sdX1 for. In particular, you must
2965 not use a partition starting at cylinder 0 for Linux swap,
2966 as that would overwrite the partition table and the boot
2967 block. You may, however, use such a partition for a UFS
2968 or EXT2 file system, as these file systems leave the first
2969 1024 bytes undisturbed. */
2970 /* On the other hand, one should not use partitions
2971 starting at block 0 in an md, or the label will
2972 be trashed. */
2973 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00002974 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002975 break;
2976 if (i < partitions && !whole_disk) {
2977 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002978 whole_disk = 1;
2979 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002980 }
2981 printf(_("Sector %d is already allocated\n"), first);
2982 } else
2983 break;
2984 }
2985 stop = cylinders * heads * sectors;
2986 stop2 = stop;
2987 for (i = 0; i < partitions; i++) {
2988 if (starts[i] > first && starts[i] < stop)
2989 stop = starts[i];
2990 }
2991 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00002992 _("Last %s or +size or +sizeM or +sizeK"),
2993 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002994 if (whole_disk)
2995 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2996 0, mesg);
2997 else if (n == 2 && !first)
2998 last = read_int(scround(first), scround(stop2), scround(stop2),
2999 scround(first), mesg);
3000 else
3001 last = read_int(scround(first), scround(stop), scround(stop),
3002 scround(first), mesg);
3003 if (display_in_cyl_units)
3004 last *= units_per_sector;
3005 if (n == 2 && !first) {
3006 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003007 whole_disk = 1;
3008 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003009 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003010 printf(_("You haven't covered the whole disk with "
3011 "the 3rd partition, but your value\n"
3012 "%d %s covers some other partition. "
3013 "Your entry has been changed\n"
3014 "to %d %s\n"),
3015 scround(last), str_units(SINGULAR),
3016 scround(stop), str_units(SINGULAR));
3017 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003018 }
3019 } else if (!whole_disk && last > stop)
3020 last = stop;
3021
Rob Landleyb73451d2006-02-24 16:29:00 +00003022 if (whole_disk)
3023 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003024 set_sun_partition(n, first, last, sys);
3025}
3026
3027static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003028sun_delete_partition(int i)
3029{
Eric Andersen040f4402003-07-30 08:40:37 +00003030 unsigned int nsec;
3031
Rob Landleyb73451d2006-02-24 16:29:00 +00003032 if (i == 2
3033 && sunlabel->infos[i].id == WHOLE_DISK
3034 && !sunlabel->partitions[i].start_cylinder
3035 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003036 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003037 "consider leaving this\n"
3038 "partition as Whole disk (5), starting at 0, with %u "
3039 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003040 sunlabel->infos[i].id = 0;
3041 sunlabel->partitions[i].num_sectors = 0;
3042}
3043
3044static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003045sun_change_sysid(int i, int sys)
3046{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003047 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003048 read_chars(
3049 _("It is highly recommended that the partition at offset 0\n"
3050 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3051 "there may destroy your partition table and bootblock.\n"
3052 "Type YES if you're very sure you would like that partition\n"
3053 "tagged with 82 (Linux swap): "));
3054 if (strcmp (line_ptr, _("YES\n")))
3055 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003056 }
3057 switch (sys) {
3058 case SUNOS_SWAP:
3059 case LINUX_SWAP:
3060 /* swaps are not mountable by default */
3061 sunlabel->infos[i].flags |= 0x01;
3062 break;
3063 default:
3064 /* assume other types are mountable;
3065 user can change it anyway */
3066 sunlabel->infos[i].flags &= ~0x01;
3067 break;
3068 }
3069 sunlabel->infos[i].id = sys;
3070}
3071
3072static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003073sun_list_table(int xtra)
3074{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003075 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003076
3077 w = strlen(disk_device);
3078 if (xtra)
3079 printf(
3080 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3081 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3082 "%d extra sects/cyl, interleave %d:1\n"
3083 "%s\n"
3084 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003085 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3086 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3087 SUN_SSWAP16(sunlabel->pcylcount),
3088 SUN_SSWAP16(sunlabel->sparecyl),
3089 SUN_SSWAP16(sunlabel->ilfact),
3090 (char *)sunlabel,
3091 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003092 else
3093 printf(
3094 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3095 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003096 disk_device, heads, sectors, cylinders,
3097 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003098
3099 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003100 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003101 for (i = 0 ; i < partitions; i++) {
3102 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003103 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3104 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003105 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3106 partname(disk_device, i+1, w), /* device */
3107 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3108 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3109 (long) scround(start), /* start */
3110 (long) scround(start+len), /* end */
3111 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3112 sunlabel->infos[i].id, /* type id */
3113 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003114 }
3115 }
3116}
3117
Eric Andersen040f4402003-07-30 08:40:37 +00003118#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3119
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003120static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003121sun_set_alt_cyl(void)
3122{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003123 sunlabel->nacyl =
3124 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003125 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003126}
3127
3128static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003129sun_set_ncyl(int cyl)
3130{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003131 sunlabel->ncyl = SUN_SSWAP16(cyl);
3132}
3133
3134static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003135sun_set_xcyl(void)
3136{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003137 sunlabel->sparecyl =
3138 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003139 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003140}
3141
3142static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003143sun_set_ilfact(void)
3144{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003145 sunlabel->ilfact =
3146 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003147 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003148}
3149
3150static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003151sun_set_rspeed(void)
3152{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003153 sunlabel->rspeed =
3154 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003155 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003156}
3157
3158static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003159sun_set_pcylcount(void)
3160{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003161 sunlabel->pcylcount =
3162 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003163 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003164}
Eric Andersen040f4402003-07-30 08:40:37 +00003165#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003166
3167static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003168sun_write_table(void)
3169{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003170 unsigned short *ush = (unsigned short *)sunlabel;
3171 unsigned short csum = 0;
3172
Rob Landleyb73451d2006-02-24 16:29:00 +00003173 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003174 csum ^= *ush++;
3175 sunlabel->csum = csum;
3176 if (lseek(fd, 0, SEEK_SET) < 0)
3177 fdisk_fatal(unable_to_seek);
3178 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3179 fdisk_fatal(unable_to_write);
3180}
3181#endif /* SUN_LABEL */
3182
3183/* DOS partition types */
3184
3185static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003186 { "\x00" "Empty" },
3187 { "\x01" "FAT12" },
3188 { "\x04" "FAT16 <32M" },
3189 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3190 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3191 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3192 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3193 { "\x0b" "Win95 FAT32" },
3194 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3195 { "\x0e" "Win95 FAT16 (LBA)" },
3196 { "\x0f" "Win95 Ext'd (LBA)" },
3197 { "\x11" "Hidden FAT12" },
3198 { "\x12" "Compaq diagnostics" },
3199 { "\x14" "Hidden FAT16 <32M" },
3200 { "\x16" "Hidden FAT16" },
3201 { "\x17" "Hidden HPFS/NTFS" },
3202 { "\x1b" "Hidden Win95 FAT32" },
3203 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3204 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3205 { "\x3c" "PartitionMagic recovery" },
3206 { "\x41" "PPC PReP Boot" },
3207 { "\x42" "SFS" },
3208 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3209 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3210 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3211 { "\x82" "Linux swap" }, /* also Solaris */
3212 { "\x83" "Linux" },
3213 { "\x84" "OS/2 hidden C: drive" },
3214 { "\x85" "Linux extended" },
3215 { "\x86" "NTFS volume set" },
3216 { "\x87" "NTFS volume set" },
3217 { "\x8e" "Linux LVM" },
3218 { "\x9f" "BSD/OS" }, /* BSDI */
3219 { "\xa0" "IBM Thinkpad hibernation" },
3220 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3221 { "\xa6" "OpenBSD" },
3222 { "\xa8" "Darwin UFS" },
3223 { "\xa9" "NetBSD" },
3224 { "\xab" "Darwin boot" },
3225 { "\xb7" "BSDI fs" },
3226 { "\xb8" "BSDI swap" },
3227 { "\xbe" "Solaris boot" },
3228 { "\xeb" "BeOS fs" },
3229 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3230 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3231 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3232 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3233 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3234 autodetect using persistent
3235 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003236#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003237 { "\x02" "XENIX root" },
3238 { "\x03" "XENIX usr" },
3239 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3240 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3241 { "\x10" "OPUS" },
3242 { "\x18" "AST SmartSleep" },
3243 { "\x24" "NEC DOS" },
3244 { "\x39" "Plan 9" },
3245 { "\x40" "Venix 80286" },
3246 { "\x4d" "QNX4.x" },
3247 { "\x4e" "QNX4.x 2nd part" },
3248 { "\x4f" "QNX4.x 3rd part" },
3249 { "\x50" "OnTrack DM" },
3250 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3251 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3252 { "\x53" "OnTrack DM6 Aux3" },
3253 { "\x54" "OnTrackDM6" },
3254 { "\x55" "EZ-Drive" },
3255 { "\x56" "Golden Bow" },
3256 { "\x5c" "Priam Edisk" },
3257 { "\x61" "SpeedStor" },
3258 { "\x64" "Novell Netware 286" },
3259 { "\x65" "Novell Netware 386" },
3260 { "\x70" "DiskSecure Multi-Boot" },
3261 { "\x75" "PC/IX" },
3262 { "\x93" "Amoeba" },
3263 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3264 { "\xa7" "NeXTSTEP" },
3265 { "\xbb" "Boot Wizard hidden" },
3266 { "\xc1" "DRDOS/sec (FAT-12)" },
3267 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3268 { "\xc6" "DRDOS/sec (FAT-16)" },
3269 { "\xc7" "Syrinx" },
3270 { "\xda" "Non-FS data" },
3271 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003272 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003273 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3274 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3275 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003276 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003277 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3278 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003279 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003280 { "\xf1" "SpeedStor" },
3281 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3282 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3283 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003284#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003285 { 0 }
3286};
3287
3288
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003289
3290/* A valid partition table sector ends in 0x55 0xaa */
3291static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003292part_table_flag(const char *b)
3293{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003294 return ((uint) b[510]) + (((uint) b[511]) << 8);
3295}
3296
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003297
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003298#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003299static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003300write_part_table_flag(char *b)
3301{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003302 b[510] = 0x55;
3303 b[511] = 0xaa;
3304}
3305
3306/* start_sect and nr_sects are stored little endian on all machines */
3307/* moreover, they are not aligned correctly */
3308static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003309store4_little_endian(unsigned char *cp, unsigned int val)
3310{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003311 cp[0] = (val & 0xff);
3312 cp[1] = ((val >> 8) & 0xff);
3313 cp[2] = ((val >> 16) & 0xff);
3314 cp[3] = ((val >> 24) & 0xff);
3315}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003316#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003317
3318static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003319read4_little_endian(const unsigned char *cp)
3320{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003321 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3322 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3323}
3324
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003325#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003326static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003327set_start_sect(struct partition *p, unsigned int start_sect)
3328{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003329 store4_little_endian(p->start4, start_sect);
3330}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003331#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003332
Eric Andersend9261492004-06-28 23:50:31 +00003333static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003334get_start_sect(const struct partition *p)
3335{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003336 return read4_little_endian(p->start4);
3337}
3338
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003339#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003340static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003341set_nr_sects(struct partition *p, int32_t nr_sects)
3342{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003343 store4_little_endian(p->size4, nr_sects);
3344}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003345#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003346
Eric Andersend9261492004-06-28 23:50:31 +00003347static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003348get_nr_sects(const struct partition *p)
3349{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003350 return read4_little_endian(p->size4);
3351}
3352
3353/* normally O_RDWR, -l option gives O_RDONLY */
3354static int type_open = O_RDWR;
3355
3356
Rob Landleyb73451d2006-02-24 16:29:00 +00003357static int ext_index; /* the prime extended partition */
3358static int listing; /* no aborts for fdisk -l */
3359static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003360#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3361static int dos_changed;
3362static int nowarn; /* no warnings for fdisk -l/-s */
3363#endif
3364
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003365
3366
Rob Landleyb73451d2006-02-24 16:29:00 +00003367static uint user_cylinders, user_heads, user_sectors;
3368static uint pt_heads, pt_sectors;
3369static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003370
Eric Andersend9261492004-06-28 23:50:31 +00003371static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003372
Eric Andersen040f4402003-07-30 08:40:37 +00003373static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003374
3375
3376static jmp_buf listingbuf;
3377
Rob Landleyb73451d2006-02-24 16:29:00 +00003378static void fdisk_fatal(enum failure why)
3379{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003380 const char *message;
3381
3382 if (listing) {
3383 close(fd);
3384 longjmp(listingbuf, 1);
3385 }
3386
3387 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003388 case unable_to_open:
3389 message = "Unable to open %s\n";
3390 break;
3391 case unable_to_read:
3392 message = "Unable to read %s\n";
3393 break;
3394 case unable_to_seek:
3395 message = "Unable to seek on %s\n";
3396 break;
3397 case unable_to_write:
3398 message = "Unable to write %s\n";
3399 break;
3400 case ioctl_error:
3401 message = "BLKGETSIZE ioctl failed on %s\n";
3402 break;
3403 default:
3404 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003405 }
3406
3407 fputc('\n', stderr);
3408 fprintf(stderr, message, disk_device);
3409 exit(1);
3410}
3411
3412static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003413seek_sector(off_t secno)
3414{
Eric Andersen0a92f352004-03-30 09:21:54 +00003415 off_t offset = secno * sector_size;
3416 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003417 fdisk_fatal(unable_to_seek);
3418}
3419
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003420#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003421static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003422write_sector(off_t secno, char *buf)
3423{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003424 seek_sector(secno);
3425 if (write(fd, buf, sector_size) != sector_size)
3426 fdisk_fatal(unable_to_write);
3427}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003428#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003429
3430/* Allocate a buffer and read a partition table sector */
3431static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003432read_pte(struct pte *pe, off_t offset)
3433{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003434 pe->offset = offset;
3435 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003436 seek_sector(offset);
3437 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3438 fdisk_fatal(unable_to_read);
3439#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003440 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003441#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003442 pe->part_table = pe->ext_pointer = NULL;
3443}
3444
3445static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003446get_partition_start(const struct pte *pe)
3447{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003448 return pe->offset + get_start_sect(pe->part_table);
3449}
3450
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003451#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003452/*
3453 * Avoid warning about DOS partitions when no DOS partition was changed.
3454 * Here a heuristic "is probably dos partition".
3455 * We might also do the opposite and warn in all cases except
3456 * for "is probably nondos partition".
3457 */
3458static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003459is_dos_partition(int t)
3460{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003461 return (t == 1 || t == 4 || t == 6 ||
3462 t == 0x0b || t == 0x0c || t == 0x0e ||
3463 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3464 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3465 t == 0xc1 || t == 0xc4 || t == 0xc6);
3466}
3467
3468static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003469menu(void)
3470{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003471#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003472 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003473 puts(_("Command action"));
3474 puts(_("\ta\ttoggle a read only flag")); /* sun */
3475 puts(_("\tb\tedit bsd disklabel"));
3476 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3477 puts(_("\td\tdelete a partition"));
3478 puts(_("\tl\tlist known partition types"));
3479 puts(_("\tm\tprint this menu"));
3480 puts(_("\tn\tadd a new partition"));
3481 puts(_("\to\tcreate a new empty DOS partition table"));
3482 puts(_("\tp\tprint the partition table"));
3483 puts(_("\tq\tquit without saving changes"));
3484 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3485 puts(_("\tt\tchange a partition's system id"));
3486 puts(_("\tu\tchange display/entry units"));
3487 puts(_("\tv\tverify the partition table"));
3488 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003489#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003490 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003491#endif
3492 } else
3493#endif
3494#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003495 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003496 puts(_("Command action"));
3497 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3498 puts(_("\tb\tedit bootfile entry")); /* sgi */
3499 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3500 puts(_("\td\tdelete a partition"));
3501 puts(_("\tl\tlist known partition types"));
3502 puts(_("\tm\tprint this menu"));
3503 puts(_("\tn\tadd a new partition"));
3504 puts(_("\to\tcreate a new empty DOS partition table"));
3505 puts(_("\tp\tprint the partition table"));
3506 puts(_("\tq\tquit without saving changes"));
3507 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3508 puts(_("\tt\tchange a partition's system id"));
3509 puts(_("\tu\tchange display/entry units"));
3510 puts(_("\tv\tverify the partition table"));
3511 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003512 } else
3513#endif
3514#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003515 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003516 puts(_("Command action"));
3517 puts(_("\tm\tprint this menu"));
3518 puts(_("\to\tcreate a new empty DOS partition table"));
3519 puts(_("\tq\tquit without saving changes"));
3520 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003521 } else
3522#endif
3523 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003524 puts(_("Command action"));
3525 puts(_("\ta\ttoggle a bootable flag"));
3526 puts(_("\tb\tedit bsd disklabel"));
3527 puts(_("\tc\ttoggle the dos compatibility flag"));
3528 puts(_("\td\tdelete a partition"));
3529 puts(_("\tl\tlist known partition types"));
3530 puts(_("\tm\tprint this menu"));
3531 puts(_("\tn\tadd a new partition"));
3532 puts(_("\to\tcreate a new empty DOS partition table"));
3533 puts(_("\tp\tprint the partition table"));
3534 puts(_("\tq\tquit without saving changes"));
3535 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3536 puts(_("\tt\tchange a partition's system id"));
3537 puts(_("\tu\tchange display/entry units"));
3538 puts(_("\tv\tverify the partition table"));
3539 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003540#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003541 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003542#endif
3543 }
3544}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003545#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3546
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003547
3548#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3549static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003550xmenu(void)
3551{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003552#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003553 if (label_sun == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003554 puts(_("Command action"));
3555 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3556 puts(_("\tc\tchange number of cylinders"));
3557 puts(_("\td\tprint the raw data in the partition table"));
3558 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3559 puts(_("\th\tchange number of heads"));
3560 puts(_("\ti\tchange interleave factor")); /*sun*/
3561 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3562 puts(_("\tm\tprint this menu"));
3563 puts(_("\tp\tprint the partition table"));
3564 puts(_("\tq\tquit without saving changes"));
3565 puts(_("\tr\treturn to main menu"));
3566 puts(_("\ts\tchange number of sectors/track"));
3567 puts(_("\tv\tverify the partition table"));
3568 puts(_("\tw\twrite table to disk and exit"));
3569 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003570 } else
3571#endif
3572#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003573 if (label_sgi == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003574 puts(_("Command action"));
3575 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3576 puts(_("\tc\tchange number of cylinders"));
3577 puts(_("\td\tprint the raw data in the partition table"));
3578 puts(_("\te\tlist extended partitions")); /* !sun */
3579 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3580 puts(_("\th\tchange number of heads"));
3581 puts(_("\tm\tprint this menu"));
3582 puts(_("\tp\tprint the partition table"));
3583 puts(_("\tq\tquit without saving changes"));
3584 puts(_("\tr\treturn to main menu"));
3585 puts(_("\ts\tchange number of sectors/track"));
3586 puts(_("\tv\tverify the partition table"));
3587 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003588 } else
3589#endif
3590#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003591 if (label_aix == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003592 puts(_("Command action"));
3593 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3594 puts(_("\tc\tchange number of cylinders"));
3595 puts(_("\td\tprint the raw data in the partition table"));
3596 puts(_("\te\tlist extended partitions")); /* !sun */
3597 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3598 puts(_("\th\tchange number of heads"));
3599 puts(_("\tm\tprint this menu"));
3600 puts(_("\tp\tprint the partition table"));
3601 puts(_("\tq\tquit without saving changes"));
3602 puts(_("\tr\treturn to main menu"));
3603 puts(_("\ts\tchange number of sectors/track"));
3604 puts(_("\tv\tverify the partition table"));
3605 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003606 } else
3607#endif
3608 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003609 puts(_("Command action"));
3610 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3611 puts(_("\tc\tchange number of cylinders"));
3612 puts(_("\td\tprint the raw data in the partition table"));
3613 puts(_("\te\tlist extended partitions")); /* !sun */
3614 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003615#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003616 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003617#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003618 puts(_("\th\tchange number of heads"));
3619 puts(_("\tm\tprint this menu"));
3620 puts(_("\tp\tprint the partition table"));
3621 puts(_("\tq\tquit without saving changes"));
3622 puts(_("\tr\treturn to main menu"));
3623 puts(_("\ts\tchange number of sectors/track"));
3624 puts(_("\tv\tverify the partition table"));
3625 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003626 }
3627}
3628#endif /* ADVANCED mode */
3629
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003630#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003631static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003632get_sys_types(void)
3633{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003634 return (
3635#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003636 label_sun == current_label_type ? sun_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003637#endif
3638#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003639 label_sgi == current_label_type ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003640#endif
3641 i386_sys_types);
3642}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003643#else
3644#define get_sys_types() i386_sys_types
3645#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003646
3647static const char *partition_type(unsigned char type)
3648{
3649 int i;
3650 const struct systypes *types = get_sys_types();
3651
Rob Landleyb73451d2006-02-24 16:29:00 +00003652 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003653 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003654 return types[i].name + 1;
3655
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003656 return _("Unknown");
3657}
3658
3659
3660#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3661static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003662get_sysid(int i)
3663{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003664 return (
3665#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003666 label_sun == current_label_type ? sunlabel->infos[i].id :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003667#endif
3668#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00003669 label_sgi == current_label_type ? sgi_get_sysid(i) :
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003670#endif
3671 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003672}
3673
3674void list_types(const struct systypes *sys)
3675{
3676 uint last[4], done = 0, next = 0, size;
3677 int i;
3678
3679 for (i = 0; sys[i].name; i++);
3680 size = i;
3681
3682 for (i = 3; i >= 0; i--)
3683 last[3 - i] = done += (size + i - done) / (i + 1);
3684 i = done = 0;
3685
3686 do {
3687 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003688 (unsigned char)sys[next].name[0],
3689 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003690 next = last[i++] + done;
3691 if (i > 3 || next >= last[i]) {
3692 i = 0;
3693 next = ++done;
3694 }
3695 } while (done < last[0]);
3696 putchar('\n');
3697}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003698#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003699
3700static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003701is_cleared_partition(const struct partition *p)
3702{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003703 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3704 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3705 get_start_sect(p) || get_nr_sects(p));
3706}
3707
3708static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003709clear_partition(struct partition *p)
3710{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003711 if (!p)
3712 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003713 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003714}
3715
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003716#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003717static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003718set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3719{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003720 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003721 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003722
3723 if (doext) {
3724 p = ptes[i].ext_pointer;
3725 offset = extended_offset;
3726 } else {
3727 p = ptes[i].part_table;
3728 offset = ptes[i].offset;
3729 }
3730 p->boot_ind = 0;
3731 p->sys_ind = sysid;
3732 set_start_sect(p, start - offset);
3733 set_nr_sects(p, stop - start + 1);
3734 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3735 start = heads*sectors*1024 - 1;
3736 set_hsc(p->head, p->sector, p->cyl, start);
3737 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3738 stop = heads*sectors*1024 - 1;
3739 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3740 ptes[i].changed = 1;
3741}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003742#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003743
3744static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003745test_c(const char **m, const char *mesg)
3746{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003747 int val = 0;
3748 if (!*m)
3749 fprintf(stderr, _("You must set"));
3750 else {
3751 fprintf(stderr, " %s", *m);
3752 val = 1;
3753 }
3754 *m = mesg;
3755 return val;
3756}
3757
3758static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003759warn_geometry(void)
3760{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003761 const char *m = NULL;
3762 int prev = 0;
3763
3764 if (!heads)
3765 prev = test_c(&m, _("heads"));
3766 if (!sectors)
3767 prev = test_c(&m, _("sectors"));
3768 if (!cylinders)
3769 prev = test_c(&m, _("cylinders"));
3770 if (!m)
3771 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003772
3773 fprintf(stderr, "%s%s.\n"
3774#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3775 "You can do this from the extra functions menu.\n"
3776#endif
3777 , prev ? _(" and ") : " ", m);
3778
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003779 return 1;
3780}
3781
3782static void update_units(void)
3783{
3784 int cyl_units = heads * sectors;
3785
3786 if (display_in_cyl_units && cyl_units)
3787 units_per_sector = cyl_units;
3788 else
3789 units_per_sector = 1; /* in sectors */
3790}
3791
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003792#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003793static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003794warn_cylinders(void)
3795{
Rob Landley5527b912006-02-25 03:46:10 +00003796 if (label_dos == current_label_type && cylinders > 1024 && !nowarn)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003797 fprintf(stderr, _("\n"
3798"The number of cylinders for this disk is set to %d.\n"
3799"There is nothing wrong with that, but this is larger than 1024,\n"
3800"and could in certain setups cause problems with:\n"
3801"1) software that runs at boot time (e.g., old versions of LILO)\n"
3802"2) booting and partitioning software from other OSs\n"
3803" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3804 cylinders);
3805}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003806#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003807
3808static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003809read_extended(int ext)
3810{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003811 int i;
3812 struct pte *pex;
3813 struct partition *p, *q;
3814
3815 ext_index = ext;
3816 pex = &ptes[ext];
3817 pex->ext_pointer = pex->part_table;
3818
3819 p = pex->part_table;
3820 if (!get_start_sect(p)) {
3821 fprintf(stderr,
3822 _("Bad offset in primary extended partition\n"));
3823 return;
3824 }
3825
Rob Landleyb73451d2006-02-24 16:29:00 +00003826 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003827 struct pte *pe = &ptes[partitions];
3828
3829 if (partitions >= MAXIMUM_PARTS) {
3830 /* This is not a Linux restriction, but
3831 this program uses arrays of size MAXIMUM_PARTS.
3832 Do not try to `improve' this test. */
3833 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003834#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003835 fprintf(stderr,
3836 _("Warning: deleting partitions after %d\n"),
3837 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003838 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003839#endif
3840 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003841 return;
3842 }
3843
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003844 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003845
3846 if (!extended_offset)
3847 extended_offset = get_start_sect(p);
3848
3849 q = p = pt_offset(pe->sectorbuffer, 0);
3850 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003851 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003852 if (pe->ext_pointer)
3853 fprintf(stderr,
3854 _("Warning: extra link "
3855 "pointer in partition table"
3856 " %d\n"), partitions + 1);
3857 else
3858 pe->ext_pointer = p;
3859 } else if (p->sys_ind) {
3860 if (pe->part_table)
3861 fprintf(stderr,
3862 _("Warning: ignoring extra "
3863 "data in partition table"
3864 " %d\n"), partitions + 1);
3865 else
3866 pe->part_table = p;
3867 }
3868 }
3869
3870 /* very strange code here... */
3871 if (!pe->part_table) {
3872 if (q != pe->ext_pointer)
3873 pe->part_table = q;
3874 else
3875 pe->part_table = q + 1;
3876 }
3877 if (!pe->ext_pointer) {
3878 if (q != pe->part_table)
3879 pe->ext_pointer = q;
3880 else
3881 pe->ext_pointer = q + 1;
3882 }
3883
3884 p = pe->ext_pointer;
3885 partitions++;
3886 }
3887
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003888#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003889 /* remove empty links */
3890 remove:
3891 for (i = 4; i < partitions; i++) {
3892 struct pte *pe = &ptes[i];
3893
3894 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003895 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003896 printf("omitting empty partition (%d)\n", i+1);
3897 delete_partition(i);
3898 goto remove; /* numbering changed */
3899 }
3900 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003901#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003902}
3903
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003904#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003905static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003906create_doslabel(void)
3907{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003908 int i;
3909
3910 fprintf(stderr,
3911 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3912 "until you decide to write them. After that, of course, the previous\n"
3913 "content won't be recoverable.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00003914
3915 current_label_type = label_dos;
3916
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003917#ifdef CONFIG_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003918 possibly_osf_label = 0;
3919#endif
3920 partitions = 4;
3921
3922 for (i = 510-64; i < 510; i++)
3923 MBRbuffer[i] = 0;
3924 write_part_table_flag(MBRbuffer);
3925 extended_offset = 0;
3926 set_all_unchanged();
3927 set_changed(0);
3928 get_boot(create_empty_dos);
3929}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003930#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003931
3932static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003933get_sectorsize(void)
3934{
Rob Landley736e5252006-02-25 03:36:00 +00003935 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003936 int arg;
3937 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3938 sector_size = arg;
3939 if (sector_size != DEFAULT_SECTOR_SIZE)
3940 printf(_("Note: sector size is %d (not %d)\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003941 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003942 }
3943}
3944
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003945static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003946get_kernel_geometry(void)
3947{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003948 struct hd_geometry geometry;
3949
3950 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3951 kern_heads = geometry.heads;
3952 kern_sectors = geometry.sectors;
3953 /* never use geometry.cylinders - it is truncated */
3954 }
3955}
3956
3957static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003958get_partition_table_geometry(void)
3959{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003960 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003961 struct partition *p;
3962 int i, h, s, hh, ss;
3963 int first = 1;
3964 int bad = 0;
3965
Eric Andersen3496fdc2006-01-30 23:09:20 +00003966 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003967 return;
3968
3969 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00003970 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003971 p = pt_offset(bufp, i);
3972 if (p->sys_ind != 0) {
3973 h = p->end_head + 1;
3974 s = (p->end_sector & 077);
3975 if (first) {
3976 hh = h;
3977 ss = s;
3978 first = 0;
3979 } else if (hh != h || ss != s)
3980 bad = 1;
3981 }
3982 }
3983
3984 if (!first && !bad) {
3985 pt_heads = hh;
3986 pt_sectors = ss;
3987 }
3988}
3989
Rob Landleyb73451d2006-02-24 16:29:00 +00003990static void
3991get_geometry(void)
3992{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003993 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003994 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003995
3996 get_sectorsize();
3997 sec_fac = sector_size / 512;
3998#ifdef CONFIG_FEATURE_SUN_LABEL
3999 guess_device_type();
4000#endif
4001 heads = cylinders = sectors = 0;
4002 kern_heads = kern_sectors = 0;
4003 pt_heads = pt_sectors = 0;
4004
4005 get_kernel_geometry();
4006 get_partition_table_geometry();
4007
4008 heads = user_heads ? user_heads :
4009 pt_heads ? pt_heads :
4010 kern_heads ? kern_heads : 255;
4011 sectors = user_sectors ? user_sectors :
4012 pt_sectors ? pt_sectors :
4013 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004014 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4015 /* got bytes */
4016 } else {
4017 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004018
4019 if (ioctl(fd, BLKGETSIZE, &longsectors))
4020 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004021 bytes = ((unsigned long long) longsectors) << 9;
4022 }
4023
4024 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004025
4026 sector_offset = 1;
4027 if (dos_compatible_flag)
4028 sector_offset = sectors;
4029
Eric Andersen040f4402003-07-30 08:40:37 +00004030 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004031 if (!cylinders)
4032 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004033}
4034
4035/*
4036 * Read MBR. Returns:
4037 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4038 * 0: found or created label
4039 * 1: I/O error
4040 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004041static int
4042get_boot(enum action what)
4043{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004044 int i;
4045
4046 partitions = 4;
4047
4048 for (i = 0; i < 4; i++) {
4049 struct pte *pe = &ptes[i];
4050
4051 pe->part_table = pt_offset(MBRbuffer, i);
4052 pe->ext_pointer = NULL;
4053 pe->offset = 0;
4054 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004055#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004056 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004057#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004058 }
4059
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004060#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004061 if (what == create_empty_sun && check_sun_label())
4062 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004063#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004064
4065 memset(MBRbuffer, 0, 512);
4066
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004067#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004068 if (what == create_empty_dos)
4069 goto got_dos_table; /* skip reading disk */
4070
4071 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004072 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4073 if (what == try_only)
4074 return 1;
4075 fdisk_fatal(unable_to_open);
4076 } else
4077 printf(_("You will not be able to write "
4078 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004079 }
4080
4081 if (512 != read(fd, MBRbuffer, 512)) {
4082 if (what == try_only)
4083 return 1;
4084 fdisk_fatal(unable_to_read);
4085 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004086#else
4087 if ((fd = open(disk_device, O_RDONLY)) < 0)
4088 return 1;
4089 if (512 != read(fd, MBRbuffer, 512))
4090 return 1;
4091#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004092
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004093 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004094
4095 update_units();
4096
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004097#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004098 if (check_sun_label())
4099 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004100#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004101
4102#ifdef CONFIG_FEATURE_SGI_LABEL
4103 if (check_sgi_label())
4104 return 0;
4105#endif
4106
4107#ifdef CONFIG_FEATURE_AIX_LABEL
4108 if (check_aix_label())
4109 return 0;
4110#endif
4111
4112#ifdef CONFIG_FEATURE_OSF_LABEL
4113 if (check_osf_label()) {
4114 possibly_osf_label = 1;
4115 if (!valid_part_table_flag(MBRbuffer)) {
Rob Landley5527b912006-02-25 03:46:10 +00004116 current_label_type = label_osf;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004117 return 0;
4118 }
4119 printf(_("This disk has both DOS and BSD magic.\n"
4120 "Give the 'b' command to go to BSD mode.\n"));
4121 }
4122#endif
4123
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004124#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004125 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004126#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004127
4128 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004129#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4130 return -1;
4131#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004132 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004133 case fdisk:
4134 fprintf(stderr,
4135 _("Device contains neither a valid DOS "
4136 "partition table, nor Sun, SGI or OSF "
4137 "disklabel\n"));
4138#ifdef __sparc__
4139#ifdef CONFIG_FEATURE_SUN_LABEL
4140 create_sunlabel();
4141#endif
4142#else
4143 create_doslabel();
4144#endif
4145 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004146 case try_only:
4147 return -1;
4148 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004149#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004150 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004151#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004152 break;
4153 default:
4154 fprintf(stderr, _("Internal error\n"));
4155 exit(1);
4156 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004157#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004158 }
4159
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004160#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004161 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004162#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004163 warn_geometry();
4164
4165 for (i = 0; i < 4; i++) {
4166 struct pte *pe = &ptes[i];
4167
Rob Landleyb73451d2006-02-24 16:29:00 +00004168 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004169 if (partitions != 4)
4170 fprintf(stderr, _("Ignoring extra extended "
4171 "partition %d\n"), i + 1);
4172 else
4173 read_extended(i);
4174 }
4175 }
4176
4177 for (i = 3; i < partitions; i++) {
4178 struct pte *pe = &ptes[i];
4179
4180 if (!valid_part_table_flag(pe->sectorbuffer)) {
4181 fprintf(stderr,
4182 _("Warning: invalid flag 0x%04x of partition "
4183 "table %d will be corrected by w(rite)\n"),
4184 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004185#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004186 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004187#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004188 }
4189 }
4190
4191 return 0;
4192}
4193
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004194#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004195/*
4196 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4197 * If the user hits Enter, DFLT is returned.
4198 * Answers like +10 are interpreted as offsets from BASE.
4199 *
4200 * There is no default if DFLT is not between LOW and HIGH.
4201 */
4202static uint
4203read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4204{
4205 uint i;
4206 int default_ok = 1;
4207 static char *ms = NULL;
4208 static int mslen = 0;
4209
4210 if (!ms || strlen(mesg)+100 > mslen) {
4211 mslen = strlen(mesg)+200;
4212 ms = xrealloc(ms,mslen);
4213 }
4214
4215 if (dflt < low || dflt > high)
4216 default_ok = 0;
4217
4218 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004219 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004220 mesg, low, high, dflt);
4221 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004222 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004223
4224 while (1) {
4225 int use_default = default_ok;
4226
4227 /* ask question and read answer */
4228 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004229 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004230 continue;
4231
Eric Andersen84bdea82004-05-19 10:49:17 +00004232 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004233 int minus = (*line_ptr == '-');
4234 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004235
Rob Landleyb73451d2006-02-24 16:29:00 +00004236 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004237
Rob Landleyb73451d2006-02-24 16:29:00 +00004238 while (isdigit(*++line_ptr))
4239 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004240
Rob Landleyb73451d2006-02-24 16:29:00 +00004241 switch (*line_ptr) {
4242 case 'c':
4243 case 'C':
4244 if (!display_in_cyl_units)
4245 i *= heads * sectors;
4246 break;
4247 case 'K':
4248 absolute = 1024;
4249 break;
4250 case 'k':
4251 absolute = 1000;
4252 break;
4253 case 'm':
4254 case 'M':
4255 absolute = 1000000;
4256 break;
4257 case 'g':
4258 case 'G':
4259 absolute = 1000000000;
4260 break;
4261 default:
4262 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004263 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004264 if (absolute) {
4265 unsigned long long bytes;
4266 unsigned long unit;
4267
4268 bytes = (unsigned long long) i * absolute;
4269 unit = sector_size * units_per_sector;
4270 bytes += unit/2; /* round */
4271 bytes /= unit;
4272 i = bytes;
4273 }
4274 if (minus)
4275 i = -i;
4276 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004277 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004278 i = atoi(line_ptr);
4279 while (isdigit(*line_ptr)) {
4280 line_ptr++;
4281 use_default = 0;
4282 }
4283 }
4284 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004285 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004286 if (i >= low && i <= high)
4287 break;
4288 else
4289 printf(_("Value out of range.\n"));
4290 }
4291 return i;
4292}
4293
Rob Landleyb73451d2006-02-24 16:29:00 +00004294static int
4295get_partition(int warn, int max)
4296{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004297 struct pte *pe;
4298 int i;
4299
4300 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4301 pe = &ptes[i];
4302
4303 if (warn) {
Rob Landley5527b912006-02-25 03:46:10 +00004304 if (
4305 (
4306 label_sun != current_label_type &&
4307 label_sgi != current_label_type &&
4308 !pe->part_table->sys_ind
4309 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004310#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004311 || (
4312 label_sun == current_label_type &&
4313 (
4314 !sunlabel->partitions[i].num_sectors
4315 || !sunlabel->infos[i].id
4316 )
4317 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004318#endif
4319#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004320 || (
4321 label_sgi == current_label_type &&
4322 !sgi_get_num_sectors(i)
4323 )
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004324#endif
Rob Landley5527b912006-02-25 03:46:10 +00004325 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004326 fprintf(stderr,
4327 _("Warning: partition %d has empty type\n"),
Rob Landley5527b912006-02-25 03:46:10 +00004328 i+1
4329 );
4330 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004331 }
4332 return i;
4333}
4334
4335static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004336get_existing_partition(int warn, int max)
4337{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004338 int pno = -1;
4339 int i;
4340
4341 for (i = 0; i < max; i++) {
4342 struct pte *pe = &ptes[i];
4343 struct partition *p = pe->part_table;
4344
4345 if (p && !is_cleared_partition(p)) {
4346 if (pno >= 0)
4347 goto not_unique;
4348 pno = i;
4349 }
4350 }
4351 if (pno >= 0) {
4352 printf(_("Selected partition %d\n"), pno+1);
4353 return pno;
4354 }
4355 printf(_("No partition is defined yet!\n"));
4356 return -1;
4357
4358 not_unique:
4359 return get_partition(warn, max);
4360}
4361
4362static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004363get_nonexisting_partition(int warn, int max)
4364{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004365 int pno = -1;
4366 int i;
4367
4368 for (i = 0; i < max; i++) {
4369 struct pte *pe = &ptes[i];
4370 struct partition *p = pe->part_table;
4371
4372 if (p && is_cleared_partition(p)) {
4373 if (pno >= 0)
4374 goto not_unique;
4375 pno = i;
4376 }
4377 }
4378 if (pno >= 0) {
4379 printf(_("Selected partition %d\n"), pno+1);
4380 return pno;
4381 }
4382 printf(_("All primary partitions have been defined already!\n"));
4383 return -1;
4384
4385 not_unique:
4386 return get_partition(warn, max);
4387}
4388
4389
4390void change_units(void)
4391{
4392 display_in_cyl_units = !display_in_cyl_units;
4393 update_units();
4394 printf(_("Changing display/entry units to %s\n"),
4395 str_units(PLURAL));
4396}
4397
4398static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004399toggle_active(int i)
4400{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004401 struct pte *pe = &ptes[i];
4402 struct partition *p = pe->part_table;
4403
Rob Landleyb73451d2006-02-24 16:29:00 +00004404 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004405 fprintf(stderr,
4406 _("WARNING: Partition %d is an extended partition\n"),
4407 i + 1);
4408 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4409 pe->changed = 1;
4410}
4411
4412static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004413toggle_dos_compatibility_flag(void)
4414{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004415 dos_compatible_flag = ~dos_compatible_flag;
4416 if (dos_compatible_flag) {
4417 sector_offset = sectors;
4418 printf(_("DOS Compatibility flag is set\n"));
4419 }
4420 else {
4421 sector_offset = 1;
4422 printf(_("DOS Compatibility flag is not set\n"));
4423 }
4424}
4425
4426static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004427delete_partition(int i)
4428{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004429 struct pte *pe = &ptes[i];
4430 struct partition *p = pe->part_table;
4431 struct partition *q = pe->ext_pointer;
4432
4433/* Note that for the fifth partition (i == 4) we don't actually
4434 * decrement partitions.
4435 */
4436
4437 if (warn_geometry())
4438 return; /* C/H/S not set */
4439 pe->changed = 1;
4440
4441#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004442 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004443 sun_delete_partition(i);
4444 return;
4445 }
4446#endif
4447#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004448 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004449 sgi_delete_partition(i);
4450 return;
4451 }
4452#endif
4453
4454 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004455 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004456 partitions = 4;
4457 ptes[ext_index].ext_pointer = NULL;
4458 extended_offset = 0;
4459 }
4460 clear_partition(p);
4461 return;
4462 }
4463
4464 if (!q->sys_ind && i > 4) {
4465 /* the last one in the chain - just delete */
4466 --partitions;
4467 --i;
4468 clear_partition(ptes[i].ext_pointer);
4469 ptes[i].changed = 1;
4470 } else {
4471 /* not the last one - further ones will be moved down */
4472 if (i > 4) {
4473 /* delete this link in the chain */
4474 p = ptes[i-1].ext_pointer;
4475 *p = *q;
4476 set_start_sect(p, get_start_sect(q));
4477 set_nr_sects(p, get_nr_sects(q));
4478 ptes[i-1].changed = 1;
4479 } else if (partitions > 5) { /* 5 will be moved to 4 */
4480 /* the first logical in a longer chain */
4481 pe = &ptes[5];
4482
4483 if (pe->part_table) /* prevent SEGFAULT */
4484 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004485 get_partition_start(pe) -
4486 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004487 pe->offset = extended_offset;
4488 pe->changed = 1;
4489 }
4490
4491 if (partitions > 5) {
4492 partitions--;
4493 while (i < partitions) {
4494 ptes[i] = ptes[i+1];
4495 i++;
4496 }
4497 } else
4498 /* the only logical: clear only */
4499 clear_partition(ptes[i].part_table);
4500 }
4501}
4502
4503static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004504change_sysid(void)
4505{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004506 int i, sys, origsys;
4507 struct partition *p;
4508
Eric Andersen040f4402003-07-30 08:40:37 +00004509#ifdef CONFIG_FEATURE_SGI_LABEL
4510 /* If sgi_label then don't use get_existing_partition,
4511 let the user select a partition, since get_existing_partition()
4512 only works for Linux like partition tables. */
Rob Landley5527b912006-02-25 03:46:10 +00004513 if (label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004514 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004515 } else {
4516 i = get_partition(0, partitions);
4517 }
4518#else
4519 i = get_existing_partition(0, partitions);
4520#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004521 if (i == -1)
4522 return;
4523 p = ptes[i].part_table;
4524 origsys = sys = get_sysid(i);
4525
4526 /* if changing types T to 0 is allowed, then
4527 the reverse change must be allowed, too */
Rob Landley5527b912006-02-25 03:46:10 +00004528 if (!sys && label_sgi != current_label_type &&
4529 label_sun != current_label_type && !get_nr_sects(p))
4530 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004531 printf(_("Partition %d does not exist yet!\n"), i + 1);
Rob Landley5527b912006-02-25 03:46:10 +00004532 }else{
4533 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004534 sys = read_hex (get_sys_types());
4535
Rob Landley5527b912006-02-25 03:46:10 +00004536 if (!sys && label_sgi != current_label_type &&
4537 label_sun != current_label_type)
4538 {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004539 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004540 "(but not to Linux). Having partitions of\n"
4541 "type 0 is probably unwise. You can delete\n"
4542 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004543 /* break; */
4544 }
4545
Rob Landley5527b912006-02-25 03:46:10 +00004546 if (label_sun != current_label_type && label_sgi != current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004547 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004548 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004549 " an extended one or vice versa\n"
4550 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004551 break;
4552 }
4553 }
4554
4555 if (sys < 256) {
4556#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004557 if (label_sun == current_label_type && i == 2 && sys != WHOLE_DISK)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004558 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004559 "as Whole disk (5),\n"
4560 "as SunOS/Solaris expects it and "
4561 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004562#endif
4563#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004564 if (label_sgi == current_label_type &&
4565 (
4566 (i == 10 && sys != ENTIRE_DISK) ||
4567 (i == 8 && sys != 0)
4568 )
4569 ){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004570 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004571 "as volume header (0),\nand "
4572 "partition 11 as entire volume (6)"
4573 "as IRIX expects it.\n\n"));
Rob Landley5527b912006-02-25 03:46:10 +00004574 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004575#endif
4576 if (sys == origsys)
4577 break;
4578#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004579 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004580 sun_change_sysid(i, sys);
4581 } else
4582#endif
4583#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004584 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004585 sgi_change_sysid(i, sys);
4586 } else
4587#endif
4588 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00004589
Rob Landleyb73451d2006-02-24 16:29:00 +00004590 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004591 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004592 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004593 ptes[i].changed = 1;
4594 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004595 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004596 dos_changed = 1;
4597 break;
4598 }
Rob Landley5527b912006-02-25 03:46:10 +00004599 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004600 }
4601}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004602#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4603
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004604
4605/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4606 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4607 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4608 * Lubkin Oct. 1991). */
4609
Rob Landleyb73451d2006-02-24 16:29:00 +00004610static void
4611long2chs(ulong ls, uint *c, uint *h, uint *s)
4612{
4613 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004614
4615 *c = ls / spc;
4616 ls = ls % spc;
4617 *h = ls / sectors;
4618 *s = ls % sectors + 1; /* sectors count from 1 */
4619}
4620
Rob Landleyb73451d2006-02-24 16:29:00 +00004621static void
4622check_consistency(const struct partition *p, int partition)
4623{
4624 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4625 uint pec, peh, pes; /* physical ending c, h, s */
4626 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4627 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004628
4629 if (!heads || !sectors || (partition >= 4))
4630 return; /* do not check extended partitions */
4631
4632/* physical beginning c, h, s */
4633 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4634 pbh = p->head;
4635 pbs = p->sector & 0x3f;
4636
4637/* physical ending c, h, s */
4638 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4639 peh = p->end_head;
4640 pes = p->end_sector & 0x3f;
4641
4642/* compute logical beginning (c, h, s) */
4643 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4644
4645/* compute logical ending (c, h, s) */
4646 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4647
4648/* Same physical / logical beginning? */
4649 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4650 printf(_("Partition %d has different physical/logical "
4651 "beginnings (non-Linux?):\n"), partition + 1);
4652 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4653 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4654 }
4655
4656/* Same physical / logical ending? */
4657 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4658 printf(_("Partition %d has different physical/logical "
4659 "endings:\n"), partition + 1);
4660 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4661 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4662 }
4663
4664#if 0
4665/* Beginning on cylinder boundary? */
4666 if (pbh != !pbc || pbs != 1) {
4667 printf(_("Partition %i does not start on cylinder "
4668 "boundary:\n"), partition + 1);
4669 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4670 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4671 }
4672#endif
4673
4674/* Ending on cylinder boundary? */
4675 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004676 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004677 partition + 1);
4678#if 0
4679 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4680 printf(_("should be (%d, %d, %d)\n"),
4681 pec, heads - 1, sectors);
4682#endif
4683 }
4684}
4685
4686static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004687list_disk_geometry(void)
4688{
Eric Andersen040f4402003-07-30 08:40:37 +00004689 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004690 long megabytes = bytes/1000000;
4691
4692 if (megabytes < 10000)
4693 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004694 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004695 else
4696 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004697 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004698 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004699 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004700 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004701 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004702 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004703 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004704 str_units(PLURAL),
4705 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004706}
4707
4708/*
4709 * Check whether partition entries are ordered by their starting positions.
4710 * Return 0 if OK. Return i if partition i should have been earlier.
4711 * Two separate checks: primary and logical partitions.
4712 */
4713static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004714wrong_p_order(int *prev)
4715{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004716 const struct pte *pe;
4717 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004718 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004719 int i, last_i = 0;
4720
4721 for (i = 0 ; i < partitions; i++) {
4722 if (i == 4) {
4723 last_i = 4;
4724 last_p_start_pos = 0;
4725 }
4726 pe = &ptes[i];
4727 if ((p = pe->part_table)->sys_ind) {
4728 p_start_pos = get_partition_start(pe);
4729
4730 if (last_p_start_pos > p_start_pos) {
4731 if (prev)
4732 *prev = last_i;
4733 return i;
4734 }
4735
4736 last_p_start_pos = p_start_pos;
4737 last_i = i;
4738 }
4739 }
4740 return 0;
4741}
4742
4743#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4744/*
4745 * Fix the chain of logicals.
4746 * extended_offset is unchanged, the set of sectors used is unchanged
4747 * The chain is sorted so that sectors increase, and so that
4748 * starting sectors increase.
4749 *
4750 * After this it may still be that cfdisk doesnt like the table.
4751 * (This is because cfdisk considers expanded parts, from link to
4752 * end of partition, and these may still overlap.)
4753 * Now
4754 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4755 * may help.
4756 */
4757static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004758fix_chain_of_logicals(void)
4759{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004760 int j, oj, ojj, sj, sjj;
4761 struct partition *pj,*pjj,tmp;
4762
4763 /* Stage 1: sort sectors but leave sector of part 4 */
4764 /* (Its sector is the global extended_offset.) */
4765 stage1:
4766 for (j = 5; j < partitions-1; j++) {
4767 oj = ptes[j].offset;
4768 ojj = ptes[j+1].offset;
4769 if (oj > ojj) {
4770 ptes[j].offset = ojj;
4771 ptes[j+1].offset = oj;
4772 pj = ptes[j].part_table;
4773 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4774 pjj = ptes[j+1].part_table;
4775 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4776 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004777 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004778 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004779 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004780 goto stage1;
4781 }
4782 }
4783
4784 /* Stage 2: sort starting sectors */
4785 stage2:
4786 for (j = 4; j < partitions-1; j++) {
4787 pj = ptes[j].part_table;
4788 pjj = ptes[j+1].part_table;
4789 sj = get_start_sect(pj);
4790 sjj = get_start_sect(pjj);
4791 oj = ptes[j].offset;
4792 ojj = ptes[j+1].offset;
4793 if (oj+sj > ojj+sjj) {
4794 tmp = *pj;
4795 *pj = *pjj;
4796 *pjj = tmp;
4797 set_start_sect(pj, ojj+sjj-oj);
4798 set_start_sect(pjj, oj+sj-ojj);
4799 goto stage2;
4800 }
4801 }
4802
4803 /* Probably something was changed */
4804 for (j = 4; j < partitions; j++)
4805 ptes[j].changed = 1;
4806}
4807
4808
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004809static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004810fix_partition_table_order(void)
4811{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004812 struct pte *pei, *pek;
4813 int i,k;
4814
4815 if (!wrong_p_order(NULL)) {
4816 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4817 return;
4818 }
4819
4820 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4821 /* partition i should have come earlier, move it */
4822 /* We have to move data in the MBR */
4823 struct partition *pi, *pk, *pe, pbuf;
4824 pei = &ptes[i];
4825 pek = &ptes[k];
4826
4827 pe = pei->ext_pointer;
4828 pei->ext_pointer = pek->ext_pointer;
4829 pek->ext_pointer = pe;
4830
4831 pi = pei->part_table;
4832 pk = pek->part_table;
4833
4834 memmove(&pbuf, pi, sizeof(struct partition));
4835 memmove(pi, pk, sizeof(struct partition));
4836 memmove(pk, &pbuf, sizeof(struct partition));
4837
4838 pei->changed = pek->changed = 1;
4839 }
4840
4841 if (i)
4842 fix_chain_of_logicals();
4843
4844 printf("Done.\n");
4845
4846}
4847#endif
4848
4849static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004850list_table(int xtra)
4851{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004852 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004853 int i, w;
4854
4855#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004856 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004857 sun_list_table(xtra);
4858 return;
4859 }
4860#endif
4861
4862#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004863 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004864 sgi_list_table(xtra);
4865 return;
4866 }
4867#endif
4868
4869 list_disk_geometry();
4870
4871#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00004872 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004873 xbsd_print_disklabel(xtra);
4874 return;
4875 }
4876#endif
4877
4878 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4879 but if the device name ends in a digit, say /dev/foo1,
4880 then the partition is called /dev/foo1p3. */
4881 w = strlen(disk_device);
4882 if (w && isdigit(disk_device[w-1]))
4883 w++;
4884 if (w < 5)
4885 w = 5;
4886
4887 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004888 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004889
4890 for (i = 0; i < partitions; i++) {
4891 const struct pte *pe = &ptes[i];
4892
4893 p = pe->part_table;
4894 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004895 off_t psects = get_nr_sects(p);
4896 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004897 unsigned int podd = 0;
4898
4899 if (sector_size < 1024) {
4900 pblocks /= (1024 / sector_size);
4901 podd = psects % (1024 / sector_size);
4902 }
4903 if (sector_size > 1024)
4904 pblocks *= (sector_size / 1024);
4905 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004906 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004907 partname(disk_device, i+1, w+2),
4908/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4909 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004910/* start */ (unsigned long long) cround(get_partition_start(pe)),
4911/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004912 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004913/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004914/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004915/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004916 check_consistency(p, i);
4917 }
4918 }
4919
4920 /* Is partition table in disk order? It need not be, but... */
4921 /* partition table entries are not checked for correct order if this
4922 is a sgi, sun or aix labeled disk... */
Rob Landley5527b912006-02-25 03:46:10 +00004923 if (label_dos == current_label_type && wrong_p_order(NULL)) {
4924 /* FIXME */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004925 printf(_("\nPartition table entries are not in disk order\n"));
4926 }
4927}
4928
4929#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4930static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004931x_list_table(int extend)
4932{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004933 const struct pte *pe;
4934 const struct partition *p;
4935 int i;
4936
4937 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4938 disk_device, heads, sectors, cylinders);
4939 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4940 for (i = 0 ; i < partitions; i++) {
4941 pe = &ptes[i];
4942 p = (extend ? pe->ext_pointer : pe->part_table);
4943 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004944 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004945 i + 1, p->boot_ind, p->head,
4946 sector(p->sector),
4947 cylinder(p->sector, p->cyl), p->end_head,
4948 sector(p->end_sector),
4949 cylinder(p->end_sector, p->end_cyl),
4950 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4951 if (p->sys_ind)
4952 check_consistency(p, i);
4953 }
4954 }
4955}
4956#endif
4957
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004958#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004959static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004960fill_bounds(off_t *first, off_t *last)
4961{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004962 int i;
4963 const struct pte *pe = &ptes[0];
4964 const struct partition *p;
4965
4966 for (i = 0; i < partitions; pe++,i++) {
4967 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004968 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004969 first[i] = 0xffffffff;
4970 last[i] = 0;
4971 } else {
4972 first[i] = get_partition_start(pe);
4973 last[i] = first[i] + get_nr_sects(p) - 1;
4974 }
4975 }
4976}
4977
4978static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004979check(int n, uint h, uint s, uint c, off_t start)
4980{
Eric Andersend9261492004-06-28 23:50:31 +00004981 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004982
4983 real_s = sector(s) - 1;
4984 real_c = cylinder(s, c);
4985 total = (real_c * sectors + real_s) * heads + h;
4986 if (!total)
4987 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4988 if (h >= heads)
4989 fprintf(stderr,
4990 _("Partition %d: head %d greater than maximum %d\n"),
4991 n, h + 1, heads);
4992 if (real_s >= sectors)
4993 fprintf(stderr, _("Partition %d: sector %d greater than "
4994 "maximum %d\n"), n, s, sectors);
4995 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004996 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4997 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004998 if (cylinders <= 1024 && start != total)
4999 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00005000 _("Partition %d: previous sectors %llu disagrees with "
5001 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005002}
5003
5004static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005005verify(void)
5006{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005007 int i, j;
5008 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00005009 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005010 struct partition *p;
5011
5012 if (warn_geometry())
5013 return;
5014
5015#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005016 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005017 verify_sun();
5018 return;
5019 }
5020#endif
5021#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005022 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005023 verify_sgi(1);
5024 return;
5025 }
5026#endif
5027
5028 fill_bounds(first, last);
5029 for (i = 0; i < partitions; i++) {
5030 struct pte *pe = &ptes[i];
5031
5032 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005033 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005034 check_consistency(p, i);
5035 if (get_partition_start(pe) < first[i])
5036 printf(_("Warning: bad start-of-data in "
5037 "partition %d\n"), i + 1);
5038 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5039 last[i]);
5040 total += last[i] + 1 - first[i];
5041 for (j = 0; j < i; j++)
5042 if ((first[i] >= first[j] && first[i] <= last[j])
5043 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5044 printf(_("Warning: partition %d overlaps "
5045 "partition %d.\n"), j + 1, i + 1);
5046 total += first[i] >= first[j] ?
5047 first[i] : first[j];
5048 total -= last[i] <= last[j] ?
5049 last[i] : last[j];
5050 }
5051 }
5052 }
5053
5054 if (extended_offset) {
5055 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005056 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005057 get_nr_sects(pex->part_table) - 1;
5058
5059 for (i = 4; i < partitions; i++) {
5060 total++;
5061 p = ptes[i].part_table;
5062 if (!p->sys_ind) {
5063 if (i != 4 || i + 1 < partitions)
5064 printf(_("Warning: partition %d "
5065 "is empty\n"), i + 1);
5066 }
5067 else if (first[i] < extended_offset ||
5068 last[i] > e_last)
5069 printf(_("Logical partition %d not entirely in "
5070 "partition %d\n"), i + 1, ext_index + 1);
5071 }
5072 }
5073
5074 if (total > heads * sectors * cylinders)
5075 printf(_("Total allocated sectors %d greater than the maximum "
5076 "%d\n"), total, heads * sectors * cylinders);
5077 else if ((total = heads * sectors * cylinders - total) != 0)
5078 printf(_("%d unallocated sectors\n"), total);
5079}
5080
5081static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005082add_partition(int n, int sys)
5083{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005084 char mesg[256]; /* 48 does not suffice in Japanese */
5085 int i, readed = 0;
5086 struct partition *p = ptes[n].part_table;
5087 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005088 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005089 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005090 first[partitions], last[partitions];
5091
5092 if (p && p->sys_ind) {
5093 printf(_("Partition %d is already defined. Delete "
5094 "it before re-adding it.\n"), n + 1);
5095 return;
5096 }
5097 fill_bounds(first, last);
5098 if (n < 4) {
5099 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005100 if (display_in_cyl_units || !total_number_of_sectors)
5101 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005102 else
Eric Andersen040f4402003-07-30 08:40:37 +00005103 llimit = total_number_of_sectors - 1;
5104 limit = llimit;
5105 if (limit != llimit)
5106 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005107 if (extended_offset) {
5108 first[ext_index] = extended_offset;
5109 last[ext_index] = get_start_sect(q) +
5110 get_nr_sects(q) - 1;
5111 }
5112 } else {
5113 start = extended_offset + sector_offset;
5114 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5115 }
5116 if (display_in_cyl_units)
5117 for (i = 0; i < partitions; i++)
5118 first[i] = (cround(first[i]) - 1) * units_per_sector;
5119
5120 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5121 do {
5122 temp = start;
5123 for (i = 0; i < partitions; i++) {
5124 int lastplusoff;
5125
5126 if (start == ptes[i].offset)
5127 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005128 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005129 if (start >= first[i] && start <= lastplusoff)
5130 start = lastplusoff + 1;
5131 }
5132 if (start > limit)
5133 break;
5134 if (start >= temp+units_per_sector && readed) {
Eric Andersend9261492004-06-28 23:50:31 +00005135 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005136 temp = start;
5137 readed = 0;
5138 }
5139 if (!readed && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005140 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005141
5142 saved_start = start;
5143 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5144 0, mesg);
5145 if (display_in_cyl_units) {
5146 start = (start - 1) * units_per_sector;
5147 if (start < saved_start) start = saved_start;
5148 }
5149 readed = 1;
5150 }
5151 } while (start != temp || !readed);
5152 if (n > 4) { /* NOT for fifth partition */
5153 struct pte *pe = &ptes[n];
5154
5155 pe->offset = start - sector_offset;
5156 if (pe->offset == extended_offset) { /* must be corrected */
5157 pe->offset++;
5158 if (sector_offset == 1)
5159 start++;
5160 }
5161 }
5162
5163 for (i = 0; i < partitions; i++) {
5164 struct pte *pe = &ptes[i];
5165
5166 if (start < pe->offset && limit >= pe->offset)
5167 limit = pe->offset - 1;
5168 if (start < first[i] && limit >= first[i])
5169 limit = first[i] - 1;
5170 }
5171 if (start > limit) {
5172 printf(_("No free sectors available\n"));
5173 if (n > 4)
5174 partitions--;
5175 return;
5176 }
5177 if (cround(start) == cround(limit)) {
5178 stop = limit;
5179 } else {
5180 snprintf(mesg, sizeof(mesg),
5181 _("Last %s or +size or +sizeM or +sizeK"),
5182 str_units(SINGULAR));
5183 stop = read_int(cround(start), cround(limit), cround(limit),
5184 cround(start), mesg);
5185 if (display_in_cyl_units) {
5186 stop = stop * units_per_sector - 1;
5187 if (stop >limit)
5188 stop = limit;
5189 }
5190 }
5191
5192 set_partition(n, 0, start, stop, sys);
5193 if (n > 4)
5194 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5195
Rob Landleyb73451d2006-02-24 16:29:00 +00005196 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005197 struct pte *pe4 = &ptes[4];
5198 struct pte *pen = &ptes[n];
5199
5200 ext_index = n;
5201 pen->ext_pointer = p;
5202 pe4->offset = extended_offset = start;
5203 pe4->sectorbuffer = xcalloc(1, sector_size);
5204 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5205 pe4->ext_pointer = pe4->part_table + 1;
5206 pe4->changed = 1;
5207 partitions = 5;
5208 }
5209}
5210
5211static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005212add_logical(void)
5213{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005214 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5215 struct pte *pe = &ptes[partitions];
5216
5217 pe->sectorbuffer = xcalloc(1, sector_size);
5218 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5219 pe->ext_pointer = pe->part_table + 1;
5220 pe->offset = 0;
5221 pe->changed = 1;
5222 partitions++;
5223 }
5224 add_partition(partitions - 1, LINUX_NATIVE);
5225}
5226
5227static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005228new_partition(void)
5229{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005230 int i, free_primary = 0;
5231
5232 if (warn_geometry())
5233 return;
5234
5235#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005236 if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005237 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5238 return;
5239 }
5240#endif
5241#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005242 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005243 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5244 return;
5245 }
5246#endif
5247#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005248 if (label_aix == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005249 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5250 "\n\tIf you want to add DOS-type partitions, create"
5251 "\n\ta new empty DOS partition table first. (Use o.)"
5252 "\n\tWARNING: "
5253 "This will destroy the present disk contents.\n"));
5254 return;
5255 }
5256#endif
5257
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005258 for (i = 0; i < 4; i++)
5259 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005260
Rob Landleyb73451d2006-02-24 16:29:00 +00005261 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005262 printf(_("The maximum number of partitions has been created\n"));
5263 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005264 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005265
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005266 if (!free_primary) {
5267 if (extended_offset)
5268 add_logical();
5269 else
5270 printf(_("You must delete some partition and add "
5271 "an extended partition first\n"));
5272 } else {
5273 char c, line[LINE_LENGTH];
5274 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5275 "partition (1-4)\n",
5276 "Command action", (extended_offset ?
5277 "l logical (5 or over)" : "e extended"));
5278 while (1) {
5279 if ((c = read_char(line)) == 'p' || c == 'P') {
5280 i = get_nonexisting_partition(0, 4);
5281 if (i >= 0)
5282 add_partition(i, LINUX_NATIVE);
5283 return;
5284 }
5285 else if (c == 'l' && extended_offset) {
5286 add_logical();
5287 return;
5288 }
5289 else if (c == 'e' && !extended_offset) {
5290 i = get_nonexisting_partition(0, 4);
5291 if (i >= 0)
5292 add_partition(i, EXTENDED);
5293 return;
5294 }
5295 else
5296 printf(_("Invalid partition number "
5297 "for type `%c'\n"), c);
5298 }
5299 }
5300}
5301
5302static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005303write_table(void)
5304{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005305 int i;
5306
Rob Landley5527b912006-02-25 03:46:10 +00005307 if (label_dos == current_label_type) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005308 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005309 if (ptes[i].changed)
5310 ptes[3].changed = 1;
5311 for (i = 3; i < partitions; i++) {
5312 struct pte *pe = &ptes[i];
5313
5314 if (pe->changed) {
5315 write_part_table_flag(pe->sectorbuffer);
5316 write_sector(pe->offset, pe->sectorbuffer);
5317 }
5318 }
5319 }
5320#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005321 else if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005322 /* no test on change? the printf below might be mistaken */
5323 sgi_write_table();
5324 }
5325#endif
5326#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005327 else if (label_sun == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005328 int needw = 0;
5329
Rob Landleyb73451d2006-02-24 16:29:00 +00005330 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005331 if (ptes[i].changed)
5332 needw = 1;
5333 if (needw)
5334 sun_write_table();
5335 }
5336#endif
5337
5338 printf(_("The partition table has been altered!\n\n"));
5339 reread_partition_table(1);
5340}
5341
Rob Landleyb73451d2006-02-24 16:29:00 +00005342static void
5343reread_partition_table(int leave)
5344{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005345 int error = 0;
5346 int i;
5347
5348 printf(_("Calling ioctl() to re-read partition table.\n"));
5349 sync();
5350 sleep(2);
5351 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5352 error = errno;
5353 } else {
5354 /* some kernel versions (1.2.x) seem to have trouble
5355 rereading the partition table, but if asked to do it
5356 twice, the second time works. - biro@yggdrasil.com */
5357 sync();
5358 sleep(2);
5359 if ((i = ioctl(fd, BLKRRPART)) != 0)
5360 error = errno;
5361 }
5362
5363 if (i) {
5364 printf(_("\nWARNING: Re-reading the partition table "
5365 "failed with error %d: %s.\n"
5366 "The kernel still uses the old table.\n"
5367 "The new table will be used "
5368 "at the next reboot.\n"),
5369 error, strerror(error));
5370 }
5371
5372 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005373 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005374 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5375 "partitions, please see the fdisk manual page for additional\n"
5376 "information.\n"));
5377
5378 if (leave) {
5379 close(fd);
5380
5381 printf(_("Syncing disks.\n"));
5382 sync();
5383 sleep(4); /* for sync() */
5384 exit(!!i);
5385 }
5386}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005387#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005388
5389#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5390#define MAX_PER_LINE 16
5391static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005392print_buffer(char *pbuffer)
5393{
5394 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005395
5396 for (i = 0, l = 0; i < sector_size; i++, l++) {
5397 if (l == 0)
5398 printf("0x%03X:", i);
5399 printf(" %02X", (unsigned char) pbuffer[i]);
5400 if (l == MAX_PER_LINE - 1) {
5401 printf("\n");
5402 l = -1;
5403 }
5404 }
5405 if (l > 0)
5406 printf("\n");
5407 printf("\n");
5408}
5409
5410
5411static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005412print_raw(void)
5413{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005414 int i;
5415
5416 printf(_("Device: %s\n"), disk_device);
5417#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
Rob Landley5527b912006-02-25 03:46:10 +00005418 if (label_sun == current_label_type || label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005419 print_buffer(MBRbuffer);
5420 else
5421#endif
5422 for (i = 3; i < partitions; i++)
5423 print_buffer(ptes[i].sectorbuffer);
5424}
5425
5426static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005427move_begin(int i)
5428{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005429 struct pte *pe = &ptes[i];
5430 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005431 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005432
5433 if (warn_geometry())
5434 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005435 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005436 printf(_("Partition %d has no data area\n"), i + 1);
5437 return;
5438 }
5439 first = get_partition_start(pe);
5440 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005441 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005442
5443 if (new != get_nr_sects(p)) {
5444 first = get_nr_sects(p) + get_start_sect(p) - new;
5445 set_nr_sects(p, first);
5446 set_start_sect(p, new);
5447 pe->changed = 1;
5448 }
5449}
5450
5451static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005452xselect(void)
5453{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005454 char c;
5455
Rob Landleyb73451d2006-02-24 16:29:00 +00005456 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005457 putchar('\n');
5458 c = tolower(read_char(_("Expert command (m for help): ")));
5459 switch (c) {
5460 case 'a':
5461#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005462 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005463 sun_set_alt_cyl();
5464#endif
5465 break;
5466 case 'b':
Rob Landley5527b912006-02-25 03:46:10 +00005467 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005468 move_begin(get_partition(0, partitions));
5469 break;
5470 case 'c':
5471 user_cylinders = cylinders =
5472 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005473 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005474#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005475 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005476 sun_set_ncyl(cylinders);
5477#endif
Rob Landley5527b912006-02-25 03:46:10 +00005478 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005479 warn_cylinders();
5480 break;
5481 case 'd':
5482 print_raw();
5483 break;
5484 case 'e':
5485#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005486 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005487 sgi_set_xcyl();
Rob Landley5527b912006-02-25 03:46:10 +00005488 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005489#endif
5490#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005491 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005492 sun_set_xcyl();
5493 else
5494#endif
Rob Landley5527b912006-02-25 03:46:10 +00005495 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005496 x_list_table(1);
5497 break;
5498 case 'f':
Rob Landley5527b912006-02-25 03:46:10 +00005499 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005500 fix_partition_table_order();
5501 break;
5502 case 'g':
5503#ifdef CONFIG_FEATURE_SGI_LABEL
5504 create_sgilabel();
5505#endif
5506 break;
5507 case 'h':
5508 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005509 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005510 update_units();
5511 break;
5512 case 'i':
5513#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005514 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005515 sun_set_ilfact();
5516#endif
5517 break;
5518 case 'o':
5519#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005520 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005521 sun_set_rspeed();
5522#endif
5523 break;
5524 case 'p':
5525#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005526 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005527 list_table(1);
5528 else
5529#endif
5530 x_list_table(0);
5531 break;
5532 case 'q':
5533 close(fd);
5534 printf("\n");
5535 exit(0);
5536 case 'r':
5537 return;
5538 case 's':
5539 user_sectors = sectors = read_int(1, sectors, 63, 0,
5540 _("Number of sectors"));
5541 if (dos_compatible_flag) {
5542 sector_offset = sectors;
5543 fprintf(stderr, _("Warning: setting "
5544 "sector offset for DOS "
5545 "compatiblity\n"));
5546 }
5547 update_units();
5548 break;
5549 case 'v':
5550 verify();
5551 break;
5552 case 'w':
5553 write_table(); /* does not return */
5554 break;
5555 case 'y':
5556#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005557 if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005558 sun_set_pcylcount();
5559#endif
5560 break;
5561 default:
5562 xmenu();
5563 }
5564 }
5565}
5566#endif /* ADVANCED mode */
5567
5568static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005569is_ide_cdrom_or_tape(const char *device)
5570{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005571 FILE *procf;
5572 char buf[100];
5573 struct stat statbuf;
5574 int is_ide = 0;
5575
5576 /* No device was given explicitly, and we are trying some
5577 likely things. But opening /dev/hdc may produce errors like
5578 "hdc: tray open or drive not ready"
5579 if it happens to be a CD-ROM drive. It even happens that
5580 the process hangs on the attempt to read a music CD.
5581 So try to be careful. This only works since 2.1.73. */
5582
5583 if (strncmp("/dev/hd", device, 7))
5584 return 0;
5585
5586 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5587 procf = fopen(buf, "r");
5588 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5589 is_ide = (!strncmp(buf, "cdrom", 5) ||
5590 !strncmp(buf, "tape", 4));
5591 else
5592 /* Now when this proc file does not exist, skip the
5593 device when it is read-only. */
5594 if (stat(device, &statbuf) == 0)
5595 is_ide = ((statbuf.st_mode & 0222) == 0);
5596
5597 if (procf)
5598 fclose(procf);
5599 return is_ide;
5600}
5601
Rob Landley5527b912006-02-25 03:46:10 +00005602
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005603static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005604try(const char *device, int user_specified)
5605{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005606 int gb;
5607
5608 disk_device = device;
5609 if (setjmp(listingbuf))
5610 return;
5611 if (!user_specified)
5612 if (is_ide_cdrom_or_tape(device))
5613 return;
5614 if ((fd = open(disk_device, type_open)) >= 0) {
5615 gb = get_boot(try_only);
5616 if (gb > 0) { /* I/O error */
5617 close(fd);
5618 } else if (gb < 0) { /* no DOS signature */
5619 list_disk_geometry();
Rob Landley5527b912006-02-25 03:46:10 +00005620 if (label_aix == current_label_type){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005621 return;
Rob Landley5527b912006-02-25 03:46:10 +00005622 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005623#ifdef CONFIG_FEATURE_OSF_LABEL
5624 if (btrydev(device) < 0)
5625#endif
5626 fprintf(stderr,
5627 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005628 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005629 close(fd);
5630 } else {
5631 close(fd);
5632 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005633#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landley5527b912006-02-25 03:46:10 +00005634 if (label_sun != current_label_type && partitions > 4){
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005635 delete_partition(ext_index);
Rob Landley5527b912006-02-25 03:46:10 +00005636 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005637#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005638 }
5639 } else {
5640 /* Ignore other errors, since we try IDE
5641 and SCSI hard disks which may not be
5642 installed on the system. */
5643 if (errno == EACCES) {
5644 fprintf(stderr, _("Cannot open %s\n"), device);
5645 return;
5646 }
5647 }
5648}
5649
5650/* for fdisk -l: try all things in /proc/partitions
5651 that look like a partition name (do not end in a digit) */
5652static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005653tryprocpt(void)
5654{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005655 FILE *procpt;
5656 char line[100], ptname[100], devname[120], *s;
5657 int ma, mi, sz;
5658
Manuel Novoa III cad53642003-03-19 09:13:01 +00005659 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005660
5661 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005662 if (sscanf(line, " %d %d %d %[^\n ]",
5663 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005664 continue;
5665 for (s = ptname; *s; s++);
5666 if (isdigit(s[-1]))
5667 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005668 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005669 try(devname, 0);
5670 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005671#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005672 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005673#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005674}
5675
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005676#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005677static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005678unknown_command(int c)
5679{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005680 printf(_("%c: unknown command\n"), c);
5681}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005682#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005683
Rob Landleyb73451d2006-02-24 16:29:00 +00005684int fdisk_main(int argc, char **argv)
5685{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005686 int c;
5687#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5688 int optl = 0;
5689#endif
5690#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5691 int opts = 0;
5692#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005693 /*
5694 * Calls:
5695 * fdisk -v
5696 * fdisk -l [-b sectorsize] [-u] device ...
5697 * fdisk -s [partition] ...
5698 * fdisk [-b sectorsize] [-u] device
5699 *
5700 * Options -C, -H, -S set the geometry.
5701 *
5702 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005703 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5704#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5705 "s"
5706#endif
5707 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005708 switch (c) {
5709 case 'b':
5710 /* Ugly: this sector size is really per device,
5711 so cannot be combined with multiple disks,
5712 and te same goes for the C/H/S options.
5713 */
5714 sector_size = atoi(optarg);
5715 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005716 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005717 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005718 sector_offset = 2;
5719 user_set_sector_size = 1;
5720 break;
5721 case 'C':
5722 user_cylinders = atoi(optarg);
5723 break;
5724 case 'H':
5725 user_heads = atoi(optarg);
5726 if (user_heads <= 0 || user_heads >= 256)
5727 user_heads = 0;
5728 break;
5729 case 'S':
5730 user_sectors = atoi(optarg);
5731 if (user_sectors <= 0 || user_sectors >= 64)
5732 user_sectors = 0;
5733 break;
5734 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005735#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005736 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005737#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005738 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005739#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005740 case 's':
5741 opts = 1;
5742 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005743#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005744 case 'u':
5745 display_in_cyl_units = 0;
5746 break;
5747 case 'V':
5748 case 'v':
5749 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5750 return 0;
5751 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005752 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005753 }
5754 }
5755
5756#if 0
5757 printf(_("This kernel finds the sector size itself - "
5758 "-b option ignored\n"));
5759#else
5760 if (user_set_sector_size && argc-optind != 1)
5761 printf(_("Warning: the -b (set sector size) option should"
5762 " be used with one specified device\n"));
5763#endif
5764
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005765#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005766 if (optl) {
5767 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005768#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005769 type_open = O_RDONLY;
5770 if (argc > optind) {
5771 int k;
5772#if __GNUC__
5773 /* avoid gcc warning:
5774 variable `k' might be clobbered by `longjmp' */
5775 (void)&k;
5776#endif
5777 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005778 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005779 try(argv[k], 1);
5780 } else {
5781 /* we no longer have default device names */
5782 /* but, we can use /proc/partitions instead */
5783 tryprocpt();
5784 }
5785 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005786#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005787 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005788#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005789
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005790#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005791 if (opts) {
5792 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005793 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005794
5795 nowarn = 1;
5796 type_open = O_RDONLY;
5797
5798 opts = argc - optind;
5799 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005800 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005801
5802 for (j = optind; j < argc; j++) {
5803 disk_device = argv[j];
5804 if ((fd = open(disk_device, type_open)) < 0)
5805 fdisk_fatal(unable_to_open);
5806 if (ioctl(fd, BLKGETSIZE, &size))
5807 fdisk_fatal(ioctl_error);
5808 close(fd);
5809 if (opts == 1)
5810 printf("%ld\n", size/2);
5811 else
5812 printf("%s: %ld\n", argv[j], size/2);
5813 }
5814 return 0;
5815 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005816#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005817
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005818#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005819 if (argc-optind == 1)
5820 disk_device = argv[optind];
5821 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005822 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005823
5824 get_boot(fdisk);
5825
5826#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005827 if (label_osf == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005828 /* OSF label, and no DOS label */
5829 printf(_("Detected an OSF/1 disklabel on %s, entering "
5830 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005831 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005832 bselect();
Rob Landley5527b912006-02-25 03:46:10 +00005833 /*Why do we do this? It seems to be counter-intuitive*/
5834 current_label_type = label_dos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005835 /* If we return we may want to make an empty DOS label? */
5836 }
5837#endif
5838
5839 while (1) {
5840 putchar('\n');
5841 c = tolower(read_char(_("Command (m for help): ")));
5842 switch (c) {
5843 case 'a':
Rob Landley5527b912006-02-25 03:46:10 +00005844 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005845 toggle_active(get_partition(1, partitions));
5846#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005847 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005848 toggle_sunflags(get_partition(1, partitions),
5849 0x01);
5850#endif
5851#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005852 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005853 sgi_set_bootpartition(
5854 get_partition(1, partitions));
5855#endif
5856 else
5857 unknown_command(c);
5858 break;
5859 case 'b':
5860#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005861 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005862 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005863 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005864 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005865 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005866 printf(_("Boot file unchanged\n"));
5867 else
5868 sgi_set_bootfile(line_ptr);
5869 } else
5870#endif
5871#ifdef CONFIG_FEATURE_OSF_LABEL
5872 bselect();
5873#endif
5874 break;
5875 case 'c':
Rob Landley5527b912006-02-25 03:46:10 +00005876 if (label_dos == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005877 toggle_dos_compatibility_flag();
5878#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005879 else if (label_sun == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005880 toggle_sunflags(get_partition(1, partitions),
5881 0x10);
5882#endif
5883#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005884 else if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005885 sgi_set_swappartition(
5886 get_partition(1, partitions));
5887#endif
5888 else
5889 unknown_command(c);
5890 break;
5891 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005892 {
Eric Andersen040f4402003-07-30 08:40:37 +00005893 int j;
5894#ifdef CONFIG_FEATURE_SGI_LABEL
5895 /* If sgi_label then don't use get_existing_partition,
5896 let the user select a partition, since
5897 get_existing_partition() only works for Linux-like
5898 partition tables */
Rob Landley5527b912006-02-25 03:46:10 +00005899 if (label_sgi != current_label_type) {
Eric Andersen040f4402003-07-30 08:40:37 +00005900 j = get_existing_partition(1, partitions);
5901 } else {
5902 j = get_partition(1, partitions);
5903 }
5904#else
5905 j = get_existing_partition(1, partitions);
5906#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005907 if (j >= 0)
5908 delete_partition(j);
5909 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005910 break;
5911 case 'i':
5912#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005913 if (label_sgi == current_label_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005914 create_sgiinfo();
5915 else
5916#endif
5917 unknown_command(c);
5918 case 'l':
5919 list_types(get_sys_types());
5920 break;
5921 case 'm':
5922 menu();
5923 break;
5924 case 'n':
5925 new_partition();
5926 break;
5927 case 'o':
5928 create_doslabel();
5929 break;
5930 case 'p':
5931 list_table(0);
5932 break;
5933 case 'q':
5934 close(fd);
5935 printf("\n");
5936 return 0;
5937 case 's':
5938#ifdef CONFIG_FEATURE_SUN_LABEL
5939 create_sunlabel();
5940#endif
5941 break;
5942 case 't':
5943 change_sysid();
5944 break;
5945 case 'u':
5946 change_units();
5947 break;
5948 case 'v':
5949 verify();
5950 break;
5951 case 'w':
5952 write_table(); /* does not return */
5953 break;
5954#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5955 case 'x':
5956#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landley5527b912006-02-25 03:46:10 +00005957 if (label_sgi == current_label_type) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005958 fprintf(stderr,
5959 _("\n\tSorry, no experts menu for SGI "
5960 "partition tables available.\n\n"));
5961 } else
5962#endif
5963
5964 xselect();
5965 break;
5966#endif
5967 default:
5968 unknown_command(c);
5969 menu();
5970 }
5971 }
5972 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005973#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005974}