blob: 0514b8935dc5e50be0a93ae92198a210d4d774b6 [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 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00005 * Licensed under the GPL v1 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00006 *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00007 * Vladimir Oleynik <dzo@simtreas.ru> 2001,2002 Busybox port
8 */
9
Eric Andersen99a75d12003-08-08 20:04:56 +000010#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000011
12#define PROC_PARTITIONS "/proc/partitions"
13
Eric Andersen256c4fd2004-05-19 09:00:00 +000014#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000015#include <sys/types.h>
16#include <sys/stat.h> /* stat */
17#include <ctype.h>
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include <errno.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <setjmp.h>
25#include <assert.h> /* assert */
26#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000027#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000028#include <sys/ioctl.h>
29#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000030#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000031
Eric Andersenacd244a2002-12-11 03:49:33 +000032#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
33
34/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000035#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000036
37#include <sys/utsname.h>
38
39#include "busybox.h"
40
41#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
42
43#define DKTYPENAMES
44
45#define _(Text) Text
46
47#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 {
96 unsigned char heads;
97 unsigned char sectors;
98 unsigned short cylinders;
99 unsigned long start;
100};
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
Eric Andersen040f4402003-07-30 08:40:37 +0000109static uint sector_size = DEFAULT_SECTOR_SIZE,
110 user_set_sector_size,
111 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_SUN_LABEL
124static int sun_label; /* looking at sun disklabel */
125#else
126#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000127#endif
128#ifdef CONFIG_FEATURE_SGI_LABEL
129static int sgi_label; /* looking at sgi disklabel */
130#else
131#define sgi_label 0
132#endif
133#ifdef CONFIG_FEATURE_AIX_LABEL
134static int aix_label; /* looking at aix disklabel */
135#else
136#define aix_label 0
137#endif
138#ifdef CONFIG_FEATURE_OSF_LABEL
139static int osf_label; /* looking at OSF/1 disklabel */
140static int possibly_osf_label;
141#else
142#define osf_label 0
143#endif
144
145#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
146
147static uint heads, sectors, cylinders;
148static void update_units(void);
149
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000150
151/*
152 * return partition name - uses static storage unless buf is supplied
153 */
154static const char *
155partname(const char *dev, int pno, int lth) {
156 static char buffer[80];
157 const char *p;
158 int w, wp;
159 int bufsiz;
160 char *bufp;
161
162 bufp = buffer;
163 bufsiz = sizeof(buffer);
164
165 w = strlen(dev);
166 p = "";
167
168 if (isdigit(dev[w-1]))
169 p = "p";
170
171 /* devfs kludge - note: fdisk partition names are not supposed
172 to equal kernel names, so there is no reason to do this */
173 if (strcmp (dev + w - 4, "disc") == 0) {
174 w -= 4;
175 p = "part";
176 }
177
178 wp = strlen(p);
179
180 if (lth) {
181 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
182 lth-wp-2, w, dev, p, pno);
183 } else {
184 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
185 }
186 return bufp;
187}
188
189struct partition {
190 unsigned char boot_ind; /* 0x80 - active */
191 unsigned char head; /* starting head */
192 unsigned char sector; /* starting sector */
193 unsigned char cyl; /* starting cylinder */
194 unsigned char sys_ind; /* What partition type */
195 unsigned char end_head; /* end head */
196 unsigned char end_sector; /* end sector */
197 unsigned char end_cyl; /* end cylinder */
198 unsigned char start4[4]; /* starting sector counting from 0 */
199 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000200} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000201
202enum failure {
203 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
204 unable_to_write
205};
206
207enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
208
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000209static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000210static int fd; /* the disk */
211static int partitions = 4; /* maximum partition + 1 */
212static uint display_in_cyl_units = 1;
213static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000214#ifdef CONFIG_FEATURE_FDISK_WRITABLE
215static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000216static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000217static void reread_partition_table(int leave);
218static void delete_partition(int i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000219static int get_partition(int warn, int max);
220static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000221static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000222#endif
223static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000224static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000225static void get_geometry(void);
226static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000227
228#define PLURAL 0
229#define SINGULAR 1
230
231#define hex_val(c) ({ \
232 char _c = (c); \
233 isdigit(_c) ? _c - '0' : \
234 tolower(_c) + 10 - 'a'; \
235 })
236
237
238#define LINE_LENGTH 800
239#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
240 (n) * sizeof(struct partition)))
241#define sector(s) ((s) & 0x3f)
242#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
243
244#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
245 ((h) + heads * cylinder(s,c)))
246#define set_hsc(h,s,c,sector) { \
247 s = sector % sectors + 1; \
248 sector /= sectors; \
249 h = sector % heads; \
250 sector /= heads; \
251 c = sector & 0xff; \
252 s |= (sector >> 2) & 0xc0; \
253 }
254
255
Eric Andersend9261492004-06-28 23:50:31 +0000256static int32_t get_start_sect(const struct partition *p);
257static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000258
259/*
260 * per partition table entry data
261 *
262 * The four primary partitions have the same sectorbuffer (MBRbuffer)
263 * and have NULL ext_pointer.
264 * Each logical partition table entry has two pointers, one for the
265 * partition and one link to the next one.
266 */
267static struct pte {
268 struct partition *part_table; /* points into sectorbuffer */
269 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000270#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000271 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000272#endif
Eric Andersend9261492004-06-28 23:50:31 +0000273 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000274 char *sectorbuffer; /* disk sector contents */
275} ptes[MAXIMUM_PARTS];
276
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000277
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000278#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000279static void
280set_all_unchanged(void) {
281 int i;
282
283 for (i = 0; i < MAXIMUM_PARTS; i++)
284 ptes[i].changed = 0;
285}
286
287static void
288set_changed(int i) {
289 ptes[i].changed = 1;
290}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000291#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000292
293#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
294static struct partition *
295get_part_table(int i) {
296 return ptes[i].part_table;
297}
298#endif
299
300static const char *
301str_units(int n) { /* n==1: use singular */
302 if (n == 1)
303 return display_in_cyl_units ? _("cylinder") : _("sector");
304 else
305 return display_in_cyl_units ? _("cylinders") : _("sectors");
306}
307
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000308static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000309valid_part_table_flag(const char *mbuffer) {
310 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000311 return (b[510] == 0x55 && b[511] == 0xaa);
312}
313
314#ifdef CONFIG_FEATURE_FDISK_WRITABLE
315static char line_buffer[LINE_LENGTH];
316
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000317/* read line; return 0 or first char */
318static int
319read_line(void)
320{
321 static int got_eof = 0;
322
323 fflush (stdout); /* requested by niles@scyld.com */
324 line_ptr = line_buffer;
325 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
326 if (feof(stdin))
327 got_eof++; /* user typed ^D ? */
328 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000329 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
330 exit(1);
331 }
332 return 0;
333 }
334 while (*line_ptr && !isgraph(*line_ptr))
335 line_ptr++;
336 return *line_ptr;
337}
338
339static char
340read_char(const char *mesg)
341{
342 do {
343 fputs(mesg, stdout);
344 } while (!read_line());
345 return *line_ptr;
346}
347
348static char
349read_chars(const char *mesg)
350{
351 fputs(mesg, stdout);
352 if (!read_line()) {
353 *line_ptr = '\n';
354 line_ptr[1] = 0;
355 }
356 return *line_ptr;
357}
358
359static int
360read_hex(const struct systypes *sys)
361{
362 int hex;
363
364 while (1)
365 {
366 read_char(_("Hex code (type L to list codes): "));
367 if (*line_ptr == 'l' || *line_ptr == 'L')
368 list_types(sys);
369 else if (isxdigit (*line_ptr))
370 {
371 hex = 0;
372 do
373 hex = hex << 4 | hex_val(*line_ptr++);
374 while (isxdigit(*line_ptr));
375 return hex;
376 }
377 }
378}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000379#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000380
381#ifdef CONFIG_FEATURE_AIX_LABEL
382/*
383 * Copyright (C) Andreas Neuper, Sep 1998.
384 * This file may be redistributed under
385 * the terms of the GNU Public License.
386 */
387
388typedef struct {
389 unsigned int magic; /* expect AIX_LABEL_MAGIC */
390 unsigned int fillbytes1[124];
391 unsigned int physical_volume_id;
392 unsigned int fillbytes2[124];
393} aix_partition;
394
395#define AIX_LABEL_MAGIC 0xc9c2d4c1
396#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
397#define AIX_INFO_MAGIC 0x00072959
398#define AIX_INFO_MAGIC_SWAPPED 0x59290700
399
400#define aixlabel ((aix_partition *)MBRbuffer)
401
402
403/*
404 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000405 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
406 * Internationalization
407 *
408 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
409 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000410*/
411
412static int aix_other_endian;
413static short aix_volumes=1;
414
415/*
416 * only dealing with free blocks here
417 */
418
419static void
420aix_info( void ) {
421 puts(
422 _("\n\tThere is a valid AIX label on this disk.\n"
423 "\tUnfortunately Linux cannot handle these\n"
424 "\tdisks at the moment. Nevertheless some\n"
425 "\tadvice:\n"
426 "\t1. fdisk will destroy its contents on write.\n"
427 "\t2. Be sure that this disk is NOT a still vital\n"
428 "\t part of a volume group. (Otherwise you may\n"
429 "\t erase the other disks as well, if unmirrored.)\n"
430 "\t3. Before deleting this physical volume be sure\n"
431 "\t to remove the disk logically from your AIX\n"
432 "\t machine. (Otherwise you become an AIXpert).")
433 );
434}
435
436static void
437aix_nolabel( void )
438{
439 aixlabel->magic = 0;
440 aix_label = 0;
441 partitions = 4;
442 memset( MBRbuffer, 0, sizeof(MBRbuffer) ); /* avoid fdisk cores */
443 return;
444}
445
446static int
447check_aix_label( void )
448{
449 if (aixlabel->magic != AIX_LABEL_MAGIC &&
450 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
451 aix_label = 0;
452 aix_other_endian = 0;
453 return 0;
454 }
455 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
456 update_units();
457 aix_label = 1;
458 partitions= 1016;
459 aix_volumes = 15;
460 aix_info();
461 aix_nolabel(); /* %% */
462 aix_label = 1; /* %% */
463 return 1;
464}
465#endif /* AIX_LABEL */
466
467#ifdef CONFIG_FEATURE_OSF_LABEL
468/*
469 * Copyright (c) 1987, 1988 Regents of the University of California.
470 * All rights reserved.
471 *
472 * Redistribution and use in source and binary forms, with or without
473 * modification, are permitted provided that the following conditions
474 * are met:
475 * 1. Redistributions of source code must retain the above copyright
476 * notice, this list of conditions and the following disclaimer.
477 * 2. Redistributions in binary form must reproduce the above copyright
478 * notice, this list of conditions and the following disclaimer in the
479 * documentation and/or other materials provided with the distribution.
480 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000481 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000482 * This product includes software developed by the University of
483 * California, Berkeley and its contributors.
484 * 4. Neither the name of the University nor the names of its contributors
485 * may be used to endorse or promote products derived from this software
486 * without specific prior written permission.
487 *
488 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
489 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
490 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
491 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
492 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
493 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
494 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
495 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
496 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
497 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
498 * SUCH DAMAGE.
499 */
500
501
502#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000503#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000504#endif
505
506#ifndef BSD_MAXPARTITIONS
507#define BSD_MAXPARTITIONS 16
508#endif
509
510#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
511
512#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
513#define BSD_LABELSECTOR 1
514#define BSD_LABELOFFSET 0
515#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
516#define BSD_LABELSECTOR 0
517#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000518#elif defined (__s390__) || defined (__s390x__)
519#define BSD_LABELSECTOR 1
520#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000521#else
522#error unknown architecture
523#endif
524
525#define BSD_BBSIZE 8192 /* size of boot area, with label */
526#define BSD_SBSIZE 8192 /* max size of fs superblock */
527
528struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000529 uint32_t d_magic; /* the magic number */
530 int16_t d_type; /* drive type */
531 int16_t d_subtype; /* controller/d_type specific */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000532 char d_typename[16]; /* type name, e.g. "eagle" */
533 char d_packname[16]; /* pack identifier */
534 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000535 uint32_t d_secsize; /* # of bytes per sector */
536 uint32_t d_nsectors; /* # of data sectors per track */
537 uint32_t d_ntracks; /* # of tracks per cylinder */
538 uint32_t d_ncylinders; /* # of data cylinders per unit */
539 uint32_t d_secpercyl; /* # of data sectors per cylinder */
540 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000541 /*
542 * Spares (bad sector replacements) below
543 * are not counted in d_nsectors or d_secpercyl.
544 * Spare sectors are assumed to be physical sectors
545 * which occupy space at the end of each track and/or cylinder.
546 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000547 uint16_t d_sparespertrack; /* # of spare sectors per track */
548 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000549 /*
550 * Alternate cylinders include maintenance, replacement,
551 * configuration description areas, etc.
552 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000553 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000554
555 /* hardware characteristics: */
556 /*
557 * d_interleave, d_trackskew and d_cylskew describe perturbations
558 * in the media format used to compensate for a slow controller.
559 * Interleave is physical sector interleave, set up by the formatter
560 * or controller when formatting. When interleaving is in use,
561 * logically adjacent sectors are not physically contiguous,
562 * but instead are separated by some number of sectors.
563 * It is specified as the ratio of physical sectors traversed
564 * per logical sector. Thus an interleave of 1:1 implies contiguous
565 * layout, while 2:1 implies that logical sector 0 is separated
566 * by one sector from logical sector 1.
567 * d_trackskew is the offset of sector 0 on track N
568 * relative to sector 0 on track N-1 on the same cylinder.
569 * Finally, d_cylskew is the offset of sector 0 on cylinder N
570 * relative to sector 0 on cylinder N-1.
571 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000572 uint16_t d_rpm; /* rotational speed */
573 uint16_t d_interleave; /* hardware sector interleave */
574 uint16_t d_trackskew; /* sector 0 skew, per track */
575 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
576 uint32_t d_headswitch; /* head switch time, usec */
577 uint32_t d_trkseek; /* track-to-track seek, usec */
578 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000579#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000580 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000581#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000582 uint32_t d_spare[NSPARE]; /* reserved for future use */
583 uint32_t d_magic2; /* the magic number (again) */
584 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000585 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000586 uint16_t d_npartitions; /* number of partitions in following */
587 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
588 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000589 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000590 uint32_t p_size; /* number of sectors in partition */
591 uint32_t p_offset; /* starting sector */
592 uint32_t p_fsize; /* filesystem basic fragment size */
593 uint8_t p_fstype; /* filesystem type, see below */
594 uint8_t p_frag; /* filesystem fragments per block */
595 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000596 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
597};
598
599/* d_type values: */
600#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
601#define BSD_DTYPE_MSCP 2 /* MSCP */
602#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
603#define BSD_DTYPE_SCSI 4 /* SCSI */
604#define BSD_DTYPE_ESDI 5 /* ESDI interface */
605#define BSD_DTYPE_ST506 6 /* ST506 etc. */
606#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
607#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
608#define BSD_DTYPE_FLOPPY 10 /* floppy */
609
610/* d_subtype values: */
611#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
612#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
613#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
614
615#ifdef DKTYPENAMES
616static const char * const xbsd_dktypenames[] = {
617 "unknown",
618 "SMD",
619 "MSCP",
620 "old DEC",
621 "SCSI",
622 "ESDI",
623 "ST506",
624 "HP-IB",
625 "HP-FL",
626 "type 9",
627 "floppy",
628 0
629};
630#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
631#endif
632
633/*
634 * Filesystem type and version.
635 * Used to interpret other filesystem-specific
636 * per-partition information.
637 */
638#define BSD_FS_UNUSED 0 /* unused */
639#define BSD_FS_SWAP 1 /* swap */
640#define BSD_FS_V6 2 /* Sixth Edition */
641#define BSD_FS_V7 3 /* Seventh Edition */
642#define BSD_FS_SYSV 4 /* System V */
643#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
644#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
645#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
646#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
647#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
648#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
649#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
650#define BSD_FS_ISOFS BSD_FS_ISO9660
651#define BSD_FS_BOOT 13 /* partition contains bootstrap */
652#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
653#define BSD_FS_HFS 15 /* Macintosh HFS */
654#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
655
656/* this is annoying, but it's also the way it is :-( */
657#ifdef __alpha__
658#define BSD_FS_EXT2 8 /* ext2 file system */
659#else
660#define BSD_FS_MSDOS 8 /* MS-DOS file system */
661#endif
662
663#ifdef DKTYPENAMES
664static const struct systypes xbsd_fstypes[] = {
665/* BSD_FS_UNUSED */ {"\x00" "unused"},
666/* BSD_FS_SWAP */ {"\x01" "swap"},
667/* BSD_FS_V6 */ {"\x02" "Version 6"},
668/* BSD_FS_V7 */ {"\x03" "Version 7"},
669/* BSD_FS_SYSV */ {"\x04" "System V"},
670/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
671/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
672/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
673#ifdef __alpha__
674/* BSD_FS_EXT2 */ {"\x08" "ext2"},
675#else
676/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
677#endif
678/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
679/* BSD_FS_OTHER */ {"\x0a" "unknown"},
680/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
681/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
682/* BSD_FS_BOOT */ {"\x0d" "boot"},
683/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
684/* BSD_FS_HFS */ {"\x0f" "HFS"},
685/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
686 { NULL }
687};
688#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
689
690#endif
691
692/*
693 * flags shared by various drives:
694 */
695#define BSD_D_REMOVABLE 0x01 /* removable media */
696#define BSD_D_ECC 0x02 /* supports ECC */
697#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
698#define BSD_D_RAMDISK 0x08 /* disk emulator */
699#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
700#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
701
702#endif /* OSF_LABEL */
703
704/*
705 * Copyright (C) Andreas Neuper, Sep 1998.
706 * This file may be modified and redistributed under
707 * the terms of the GNU Public License.
708 */
709
710struct device_parameter { /* 48 bytes */
711 unsigned char skew;
712 unsigned char gap1;
713 unsigned char gap2;
714 unsigned char sparecyl;
715 unsigned short pcylcount;
716 unsigned short head_vol0;
717 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
718 unsigned char cmd_tag_queue_depth;
719 unsigned char unused0;
720 unsigned short unused1;
721 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
722 unsigned short bytes;
723 unsigned short ilfact;
724 unsigned int flags; /* controller flags */
725 unsigned int datarate;
726 unsigned int retries_on_error;
727 unsigned int ms_per_word;
728 unsigned short xylogics_gap1;
729 unsigned short xylogics_syncdelay;
730 unsigned short xylogics_readdelay;
731 unsigned short xylogics_gap2;
732 unsigned short xylogics_readgate;
733 unsigned short xylogics_writecont;
734};
735
736#define SGI_VOLHDR 0x00
737/* 1 and 2 were used for drive types no longer supported by SGI */
738#define SGI_SWAP 0x03
739/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
740#define SGI_VOLUME 0x06
741#define SGI_EFS 0x07
742#define SGI_LVOL 0x08
743#define SGI_RLVOL 0x09
744#define SGI_XFS 0x0a
745#define SGI_XFSLOG 0x0b
746#define SGI_XLV 0x0c
747#define SGI_XVM 0x0d
748#define ENTIRE_DISK SGI_VOLUME
749/*
750 * controller flags
751 */
752#define SECTOR_SLIP 0x01
753#define SECTOR_FWD 0x02
754#define TRACK_FWD 0x04
755#define TRACK_MULTIVOL 0x08
756#define IGNORE_ERRORS 0x10
757#define RESEEK 0x20
758#define ENABLE_CMDTAGQ 0x40
759
760typedef struct {
761 unsigned int magic; /* expect SGI_LABEL_MAGIC */
762 unsigned short boot_part; /* active boot partition */
763 unsigned short swap_part; /* active swap partition */
764 unsigned char boot_file[16]; /* name of the bootfile */
765 struct device_parameter devparam; /* 1 * 48 bytes */
766 struct volume_directory { /* 15 * 16 bytes */
767 unsigned char vol_file_name[8]; /* a character array */
768 unsigned int vol_file_start; /* number of logical block */
769 unsigned int vol_file_size; /* number of bytes */
770 } directory[15];
771 struct sgi_partition { /* 16 * 12 bytes */
772 unsigned int num_sectors; /* number of blocks */
773 unsigned int start_sector; /* must be cylinder aligned */
774 unsigned int id;
775 } partitions[16];
776 unsigned int csum;
777 unsigned int fillbytes;
778} sgi_partition;
779
780typedef struct {
781 unsigned int magic; /* looks like a magic number */
782 unsigned int a2;
783 unsigned int a3;
784 unsigned int a4;
785 unsigned int b1;
786 unsigned short b2;
787 unsigned short b3;
788 unsigned int c[16];
789 unsigned short d[3];
790 unsigned char scsi_string[50];
791 unsigned char serial[137];
792 unsigned short check1816;
793 unsigned char installer[225];
794} sgiinfo;
795
796#define SGI_LABEL_MAGIC 0x0be5a941
797#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
798#define SGI_INFO_MAGIC 0x00072959
799#define SGI_INFO_MAGIC_SWAPPED 0x59290700
800#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000801 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000802#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000803 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000804
805#define sgilabel ((sgi_partition *)MBRbuffer)
806#define sgiparam (sgilabel->devparam)
807
808typedef struct {
809 unsigned char info[128]; /* Informative text string */
810 unsigned char spare0[14];
811 struct sun_info {
812 unsigned char spare1;
813 unsigned char id;
814 unsigned char spare2;
815 unsigned char flags;
816 } infos[8];
817 unsigned char spare1[246]; /* Boot information etc. */
818 unsigned short rspeed; /* Disk rotational speed */
819 unsigned short pcylcount; /* Physical cylinder count */
820 unsigned short sparecyl; /* extra sects per cylinder */
821 unsigned char spare2[4]; /* More magic... */
822 unsigned short ilfact; /* Interleave factor */
823 unsigned short ncyl; /* Data cylinder count */
824 unsigned short nacyl; /* Alt. cylinder count */
825 unsigned short ntrks; /* Tracks per cylinder */
826 unsigned short nsect; /* Sectors per track */
827 unsigned char spare3[4]; /* Even more magic... */
828 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000829 uint32_t start_cylinder;
830 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000831 } partitions[8];
832 unsigned short magic; /* Magic number */
833 unsigned short csum; /* Label xor'd checksum */
834} sun_partition;
835
Eric Andersen040f4402003-07-30 08:40:37 +0000836
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000837#define SUN_LABEL_MAGIC 0xDABE
838#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
839#define sunlabel ((sun_partition *)MBRbuffer)
840#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000841 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000842#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000843 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000844
Eric Andersend3652bf2003-08-06 09:07:37 +0000845
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000846#ifdef CONFIG_FEATURE_OSF_LABEL
847/*
848 Changes:
849 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
850
851 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
852 support for OSF/1 disklabels on Alpha.
853 Also fixed unaligned accesses in alpha_bootblock_checksum()
854*/
855
856#define FREEBSD_PARTITION 0xa5
857#define NETBSD_PARTITION 0xa9
858
859static void xbsd_delete_part (void);
860static void xbsd_new_part (void);
861static void xbsd_write_disklabel (void);
862static int xbsd_create_disklabel (void);
863static void xbsd_edit_disklabel (void);
864static void xbsd_write_bootstrap (void);
865static void xbsd_change_fstype (void);
866static int xbsd_get_part_index (int max);
867static int xbsd_check_new_partition (int *i);
868static void xbsd_list_types (void);
869static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000870static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000871static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
872static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
873
874#if defined (__alpha__)
875static void alpha_bootblock_checksum (char *boot);
876#endif
877
878#if !defined (__alpha__)
879static int xbsd_translate_fstype (int linux_type);
880static void xbsd_link_part (void);
881static struct partition *xbsd_part;
882static int xbsd_part_index;
883#endif
884
885#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000886/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000887static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000888#else
889static char disklabelbuffer[BSD_BBSIZE];
890#endif
891
892static struct xbsd_disklabel xbsd_dlabel;
893
894#define bsd_cround(n) \
895 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
896
897/*
898 * Test whether the whole disk has BSD disk label magic.
899 *
900 * Note: often reformatting with DOS-type label leaves the BSD magic,
901 * so this does not mean that there is a BSD disk label.
902 */
903static int
904check_osf_label(void) {
905 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
906 return 0;
907 return 1;
908}
909
910static void xbsd_print_disklabel(int);
911
912static int
Glenn L McGrath35631a62002-12-08 11:51:05 +0000913btrydev (const char * dev) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000914 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
915 return -1;
916 printf(_("\nBSD label for device: %s\n"), dev);
917 xbsd_print_disklabel (0);
918 return 0;
919}
920
921static void
922bmenu (void) {
923 puts (_("Command action"));
924 puts (_("\td\tdelete a BSD partition"));
925 puts (_("\te\tedit drive data"));
926 puts (_("\ti\tinstall bootstrap"));
927 puts (_("\tl\tlist known filesystem types"));
928 puts (_("\tm\tprint this menu"));
929 puts (_("\tn\tadd a new BSD partition"));
930 puts (_("\tp\tprint BSD partition table"));
931 puts (_("\tq\tquit without saving changes"));
932 puts (_("\tr\treturn to main menu"));
933 puts (_("\ts\tshow complete disklabel"));
934 puts (_("\tt\tchange a partition's filesystem id"));
935 puts (_("\tu\tchange units (cylinders/sectors)"));
936 puts (_("\tw\twrite disklabel to disk"));
937#if !defined (__alpha__)
938 puts (_("\tx\tlink BSD partition to non-BSD partition"));
939#endif
940}
941
942#if !defined (__alpha__)
943static int
944hidden(int type) {
945 return type ^ 0x10;
946}
947
948static int
949is_bsd_partition_type(int type) {
950 return (type == FREEBSD_PARTITION ||
951 type == hidden(FREEBSD_PARTITION) ||
952 type == NETBSD_PARTITION ||
953 type == hidden(NETBSD_PARTITION));
954}
955#endif
956
957static void
958bselect (void) {
959#if !defined (__alpha__)
960 int t, ss;
961 struct partition *p;
962
963 for (t=0; t<4; t++) {
964 p = get_part_table(t);
965 if (p && is_bsd_partition_type(p->sys_ind)) {
966 xbsd_part = p;
967 xbsd_part_index = t;
968 ss = get_start_sect(xbsd_part);
969 if (ss == 0) {
970 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
971 partname(disk_device, t+1, 0));
972 return;
973 }
974 printf (_("Reading disklabel of %s at sector %d.\n"),
975 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
976 if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
977 if (xbsd_create_disklabel () == 0)
978 return;
979 break;
980 }
981 }
982
983 if (t == 4) {
984 printf (_("There is no *BSD partition on %s.\n"), disk_device);
985 return;
986 }
987
988#elif defined (__alpha__)
989
990 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
991 if (xbsd_create_disklabel () == 0)
992 exit ( EXIT_SUCCESS );
993
994#endif
995
996 while (1) {
997 putchar ('\n');
998 switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
999 case 'd':
1000 xbsd_delete_part ();
1001 break;
1002 case 'e':
1003 xbsd_edit_disklabel ();
1004 break;
1005 case 'i':
1006 xbsd_write_bootstrap ();
1007 break;
1008 case 'l':
1009 xbsd_list_types ();
1010 break;
1011 case 'n':
1012 xbsd_new_part ();
1013 break;
1014 case 'p':
1015 xbsd_print_disklabel (0);
1016 break;
1017 case 'q':
1018 close (fd);
1019 exit ( EXIT_SUCCESS );
1020 case 'r':
1021 return;
1022 case 's':
1023 xbsd_print_disklabel (1);
1024 break;
1025 case 't':
1026 xbsd_change_fstype ();
1027 break;
1028 case 'u':
1029 change_units();
1030 break;
1031 case 'w':
1032 xbsd_write_disklabel ();
1033 break;
1034#if !defined (__alpha__)
1035 case 'x':
1036 xbsd_link_part ();
1037 break;
1038#endif
1039 default:
1040 bmenu ();
1041 break;
1042 }
1043 }
1044}
1045
1046static void
1047xbsd_delete_part (void)
1048{
1049 int i;
1050
1051 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1052 xbsd_dlabel.d_partitions[i].p_size = 0;
1053 xbsd_dlabel.d_partitions[i].p_offset = 0;
1054 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1055 if (xbsd_dlabel.d_npartitions == i + 1)
1056 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1057 xbsd_dlabel.d_npartitions--;
1058}
1059
1060static void
1061xbsd_new_part (void)
1062{
Eric Andersend9261492004-06-28 23:50:31 +00001063 off_t begin, end;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001064 char mesg[256];
1065 int i;
1066
1067 if (!xbsd_check_new_partition (&i))
1068 return;
1069
1070#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1071 begin = get_start_sect(xbsd_part);
1072 end = begin + get_nr_sects(xbsd_part) - 1;
1073#else
1074 begin = 0;
1075 end = xbsd_dlabel.d_secperunit - 1;
1076#endif
1077
1078 snprintf (mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1079 begin = read_int (bsd_cround (begin), bsd_cround (begin), bsd_cround (end),
1080 0, mesg);
1081
1082 if (display_in_cyl_units)
1083 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
1084
1085 snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1086 str_units(SINGULAR));
1087 end = read_int (bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1088 bsd_cround (begin), mesg);
1089
1090 if (display_in_cyl_units)
1091 end = end * xbsd_dlabel.d_secpercyl - 1;
1092
1093 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1094 xbsd_dlabel.d_partitions[i].p_offset = begin;
1095 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1096}
1097
1098static void
1099xbsd_print_disklabel (int show_all) {
1100 struct xbsd_disklabel *lp = &xbsd_dlabel;
1101 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001102 int i, j;
1103
1104 if (show_all) {
1105#if defined (__alpha__)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001106 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001107#else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001108 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001109#endif
1110 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001111 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001112 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001113 printf(_("type: %d\n"), lp->d_type);
1114 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1115 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1116 printf(_("flags:"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001117 if (lp->d_flags & BSD_D_REMOVABLE)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001118 printf(_(" removable"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001119 if (lp->d_flags & BSD_D_ECC)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001120 printf(_(" ecc"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001121 if (lp->d_flags & BSD_D_BADSECT)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001122 printf(_(" badsect"));
1123 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001124 /* On various machines the fields of *lp are short/int/long */
1125 /* In order to avoid problems, we cast them all to long. */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001126 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1127 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1128 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1129 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1130 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1131 printf(_("rpm: %d\n"), lp->d_rpm);
1132 printf(_("interleave: %d\n"), lp->d_interleave);
1133 printf(_("trackskew: %d\n"), lp->d_trackskew);
1134 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1135 printf(_("headswitch: %ld\t\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001136 (long) lp->d_headswitch);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001137 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001138 (long) lp->d_trkseek);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001139 printf(_("drivedata: "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001140 for (i = NDDATA - 1; i >= 0; i--)
1141 if (lp->d_drivedata[i])
1142 break;
1143 if (i < 0)
1144 i = 0;
1145 for (j = 0; j <= i; j++)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001146 printf("%ld ", (long) lp->d_drivedata[j]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001147 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001148 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1149 printf(_("# start end size fstype [fsize bsize cpg]\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001150 pp = lp->d_partitions;
1151 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1152 if (pp->p_size) {
1153 if (display_in_cyl_units && lp->d_secpercyl) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001154 printf(" %c: %8ld%c %8ld%c %8ld%c ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001155 'a' + i,
1156 (long) pp->p_offset / lp->d_secpercyl + 1,
1157 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1158 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
1159 / lp->d_secpercyl,
1160 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1161 (long) pp->p_size / lp->d_secpercyl,
1162 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
1163 } else {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001164 printf(" %c: %8ld %8ld %8ld ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001165 'a' + i,
1166 (long) pp->p_offset,
1167 (long) pp->p_offset + pp->p_size - 1,
1168 (long) pp->p_size);
1169 }
1170 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001171 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001172 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001173 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001174 switch (pp->p_fstype) {
1175 case BSD_FS_UNUSED:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001176 printf(" %5ld %5ld %5.5s ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001177 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1178 break;
1179
1180 case BSD_FS_BSDFFS:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001181 printf(" %5ld %5ld %5d ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001182 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
1183 pp->p_cpg);
1184 break;
1185
1186 default:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001187 printf("%22.22s", "");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001188 break;
1189 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001190 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001191 }
1192 }
1193}
1194
1195static void
1196xbsd_write_disklabel (void) {
1197#if defined (__alpha__)
1198 printf (_("Writing disklabel to %s.\n"), disk_device);
1199 xbsd_writelabel (NULL, &xbsd_dlabel);
1200#else
1201 printf (_("Writing disklabel to %s.\n"),
1202 partname(disk_device, xbsd_part_index+1, 0));
1203 xbsd_writelabel (xbsd_part, &xbsd_dlabel);
1204#endif
1205 reread_partition_table(0); /* no exit yet */
1206}
1207
1208static int
1209xbsd_create_disklabel (void) {
1210 char c;
1211
1212#if defined (__alpha__)
1213 fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
1214#else
1215 fprintf (stderr, _("%s contains no disklabel.\n"),
1216 partname(disk_device, xbsd_part_index+1, 0));
1217#endif
1218
1219 while (1) {
1220 c = read_char (_("Do you want to create a disklabel? (y/n) "));
1221 if (c == 'y' || c == 'Y') {
1222 if (xbsd_initlabel (
Eric Andersen040f4402003-07-30 08:40:37 +00001223#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
1224 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001225 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001226#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001227 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001228#endif
1229 ) == 1) {
1230 xbsd_print_disklabel (1);
1231 return 1;
1232 } else
1233 return 0;
1234 } else if (c == 'n')
1235 return 0;
1236 }
1237}
1238
1239static int
1240edit_int (int def, char *mesg)
1241{
1242 do {
1243 fputs (mesg, stdout);
1244 printf (" (%d): ", def);
1245 if (!read_line ())
1246 return def;
1247 }
1248 while (!isdigit (*line_ptr));
1249 return atoi (line_ptr);
1250}
1251
1252static void
1253xbsd_edit_disklabel (void)
1254{
1255 struct xbsd_disklabel *d;
1256
1257 d = &xbsd_dlabel;
1258
1259#if defined (__alpha__) || defined (__ia64__)
1260 d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,_("bytes/sector"));
1261 d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,_("sectors/track"));
1262 d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,_("tracks/cylinder"));
1263 d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,_("cylinders"));
1264#endif
1265
1266 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
1267 while (1)
1268 {
1269 d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
1270 _("sectors/cylinder"));
1271 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
1272 break;
1273
1274 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1275 }
1276 d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,_("rpm"));
1277 d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
1278 d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
1279 d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,_("cylinderskew"));
1280 d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,_("headswitch"));
1281 d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,_("track-to-track seek"));
1282
1283 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1284}
1285
1286static int
1287xbsd_get_bootstrap (char *path, void *ptr, int size)
1288{
1289 int fdb;
1290
1291 if ((fdb = open (path, O_RDONLY)) < 0)
1292 {
1293 perror (path);
1294 return 0;
1295 }
1296 if (read (fdb, ptr, size) < 0)
1297 {
1298 perror (path);
1299 close (fdb);
1300 return 0;
1301 }
1302 printf (" ... %s\n", path);
1303 close (fdb);
1304 return 1;
1305}
1306
1307static void
1308sync_disks (void)
1309{
1310 printf (_("\nSyncing disks.\n"));
1311 sync ();
1312 sleep (4);
1313}
1314
1315static void
1316xbsd_write_bootstrap (void)
1317{
1318 char *bootdir = BSD_LINUX_BOOTDIR;
1319 char path[MAXPATHLEN];
1320 char *dkbasename;
1321 struct xbsd_disklabel dl;
1322 char *d, *p, *e;
1323 int sector;
1324
1325 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1326 dkbasename = "sd";
1327 else
1328 dkbasename = "wd";
1329
1330 printf (_("Bootstrap: %sboot -> boot%s (%s): "),
1331 dkbasename, dkbasename, dkbasename);
1332 if (read_line ()) {
1333 line_ptr[strlen (line_ptr)-1] = '\0';
1334 dkbasename = line_ptr;
1335 }
1336 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1337 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1338 return;
1339
1340 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1341 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1342 bcopy (d, &dl, sizeof (struct xbsd_disklabel));
1343
1344 /* The disklabel will be overwritten by 0's from bootxx anyway */
Bernhard Reutner-Fischer30385572006-01-31 17:57:48 +00001345 memset (d, 0, sizeof (struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001346
1347 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1348 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1349 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1350 return;
1351
1352 e = d + sizeof (struct xbsd_disklabel);
1353 for (p=d; p < e; p++)
1354 if (*p) {
1355 fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
1356 exit ( EXIT_FAILURE );
1357 }
1358
1359 bcopy (&dl, d, sizeof (struct xbsd_disklabel));
1360
1361#if defined (__powerpc__) || defined (__hppa__)
1362 sector = 0;
1363#elif defined (__alpha__)
1364 sector = 0;
1365 alpha_bootblock_checksum (disklabelbuffer);
1366#else
1367 sector = get_start_sect(xbsd_part);
1368#endif
1369
Eric Andersen0a92f352004-03-30 09:21:54 +00001370 if (lseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001371 fdisk_fatal (unable_to_seek);
1372 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1373 fdisk_fatal (unable_to_write);
1374
1375#if defined (__alpha__)
1376 printf (_("Bootstrap installed on %s.\n"), disk_device);
1377#else
1378 printf (_("Bootstrap installed on %s.\n"),
1379 partname (disk_device, xbsd_part_index+1, 0));
1380#endif
1381
1382 sync_disks ();
1383}
1384
1385static void
1386xbsd_change_fstype (void)
1387{
1388 int i;
1389
1390 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1391 xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
1392}
1393
1394static int
1395xbsd_get_part_index (int max)
1396{
1397 char prompt[256];
1398 char l;
1399
1400 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1401 do
1402 l = tolower (read_char (prompt));
1403 while (l < 'a' || l > 'a' + max - 1);
1404 return l - 'a';
1405}
1406
1407static int
1408xbsd_check_new_partition (int *i) {
1409
1410 /* room for more? various BSD flavours have different maxima */
1411 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1412 int t;
1413
1414 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1415 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1416 break;
1417
1418 if (t == BSD_MAXPARTITIONS) {
1419 fprintf (stderr, _("The maximum number of partitions "
1420 "has been created\n"));
1421 return 0;
1422 }
1423 }
1424
1425 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1426
1427 if (*i >= xbsd_dlabel.d_npartitions)
1428 xbsd_dlabel.d_npartitions = (*i) + 1;
1429
1430 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1431 fprintf (stderr, _("This partition already exists.\n"));
1432 return 0;
1433 }
1434
1435 return 1;
1436}
1437
1438static void
1439xbsd_list_types (void) {
1440 list_types (xbsd_fstypes);
1441}
1442
1443static u_short
1444xbsd_dkcksum (struct xbsd_disklabel *lp) {
1445 u_short *start, *end;
1446 u_short sum = 0;
1447
1448 start = (u_short *) lp;
1449 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1450 while (start < end)
1451 sum ^= *start++;
1452 return sum;
1453}
1454
1455static int
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001456xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001457 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001458
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001459 get_geometry ();
Bernhard Reutner-Fischer30385572006-01-31 17:57:48 +00001460 memset (d, 0, sizeof (struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001461
1462 d -> d_magic = BSD_DISKMAGIC;
1463
1464 if (strncmp (disk_device, "/dev/sd", 7) == 0)
1465 d -> d_type = BSD_DTYPE_SCSI;
1466 else
1467 d -> d_type = BSD_DTYPE_ST506;
1468
1469#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
1470 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
1471#endif
1472
1473#if !defined (__alpha__)
1474 d -> d_flags = BSD_D_DOSPART;
1475#else
1476 d -> d_flags = 0;
1477#endif
1478 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001479 d -> d_nsectors = sectors; /* sectors/track */
1480 d -> d_ntracks = heads; /* tracks/cylinder (heads) */
1481 d -> d_ncylinders = cylinders;
1482 d -> d_secpercyl = sectors * heads;/* sectors/cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001483 if (d -> d_secpercyl == 0)
1484 d -> d_secpercyl = 1; /* avoid segfaults */
1485 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1486
1487 d -> d_rpm = 3600;
1488 d -> d_interleave = 1;
1489 d -> d_trackskew = 0;
1490 d -> d_cylskew = 0;
1491 d -> d_headswitch = 0;
1492 d -> d_trkseek = 0;
1493
1494 d -> d_magic2 = BSD_DISKMAGIC;
1495 d -> d_bbsize = BSD_BBSIZE;
1496 d -> d_sbsize = BSD_SBSIZE;
1497
1498#if !defined (__alpha__)
1499 d -> d_npartitions = 4;
1500 pp = &d -> d_partitions[2]; /* Partition C should be
1501 the NetBSD partition */
1502 pp -> p_offset = get_start_sect(p);
1503 pp -> p_size = get_nr_sects(p);
1504 pp -> p_fstype = BSD_FS_UNUSED;
1505 pp = &d -> d_partitions[3]; /* Partition D should be
1506 the whole disk */
1507 pp -> p_offset = 0;
1508 pp -> p_size = d -> d_secperunit;
1509 pp -> p_fstype = BSD_FS_UNUSED;
1510#elif defined (__alpha__)
1511 d -> d_npartitions = 3;
1512 pp = &d -> d_partitions[2]; /* Partition C should be
1513 the whole disk */
1514 pp -> p_offset = 0;
1515 pp -> p_size = d -> d_secperunit;
1516 pp -> p_fstype = BSD_FS_UNUSED;
1517#endif
1518
1519 return 1;
1520}
1521
1522/*
1523 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1524 * If it has the right magic, return 1.
1525 */
1526static int
1527xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1528{
1529 int t, sector;
1530
1531 /* p is used only to get the starting sector */
1532#if !defined (__alpha__)
1533 sector = (p ? get_start_sect(p) : 0);
1534#elif defined (__alpha__)
1535 sector = 0;
1536#endif
1537
Eric Andersen0a92f352004-03-30 09:21:54 +00001538 if (lseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001539 fdisk_fatal (unable_to_seek);
1540 if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
1541 fdisk_fatal (unable_to_read);
1542
1543 bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1544 d, sizeof (struct xbsd_disklabel));
1545
1546 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
1547 return 0;
1548
1549 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1550 d -> d_partitions[t].p_size = 0;
1551 d -> d_partitions[t].p_offset = 0;
1552 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
1553 }
1554
1555 if (d -> d_npartitions > BSD_MAXPARTITIONS)
1556 fprintf (stderr, _("Warning: too many partitions "
1557 "(%d, maximum is %d).\n"),
1558 d -> d_npartitions, BSD_MAXPARTITIONS);
1559 return 1;
1560}
1561
1562static int
1563xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1564{
Eric Andersen040f4402003-07-30 08:40:37 +00001565 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001566
1567#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1568 sector = get_start_sect(p) + BSD_LABELSECTOR;
1569#else
1570 sector = BSD_LABELSECTOR;
1571#endif
1572
1573 d -> d_checksum = 0;
1574 d -> d_checksum = xbsd_dkcksum (d);
1575
1576 /* This is necessary if we want to write the bootstrap later,
1577 otherwise we'd write the old disklabel with the bootstrap.
1578 */
1579 bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1580 sizeof (struct xbsd_disklabel));
1581
1582#if defined (__alpha__) && BSD_LABELSECTOR == 0
1583 alpha_bootblock_checksum (disklabelbuffer);
Eric Andersen0a92f352004-03-30 09:21:54 +00001584 if (lseek (fd, 0, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001585 fdisk_fatal (unable_to_seek);
1586 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1587 fdisk_fatal (unable_to_write);
1588#else
Eric Andersen0a92f352004-03-30 09:21:54 +00001589 if (lseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001590 SEEK_SET) == -1)
1591 fdisk_fatal (unable_to_seek);
1592 if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel)))
1593 fdisk_fatal (unable_to_write);
1594#endif
1595
1596 sync_disks ();
1597
1598 return 1;
1599}
1600
1601
1602#if !defined (__alpha__)
1603static int
1604xbsd_translate_fstype (int linux_type)
1605{
1606 switch (linux_type)
1607 {
1608 case 0x01: /* DOS 12-bit FAT */
1609 case 0x04: /* DOS 16-bit <32M */
1610 case 0x06: /* DOS 16-bit >=32M */
1611 case 0xe1: /* DOS access */
1612 case 0xe3: /* DOS R/O */
1613 case 0xf2: /* DOS secondary */
1614 return BSD_FS_MSDOS;
1615 case 0x07: /* OS/2 HPFS */
1616 return BSD_FS_HPFS;
1617 default:
1618 return BSD_FS_OTHER;
1619 }
1620}
1621
1622static void
1623xbsd_link_part (void)
1624{
1625 int k, i;
1626 struct partition *p;
1627
1628 k = get_partition (1, partitions);
1629
1630 if (!xbsd_check_new_partition (&i))
1631 return;
1632
1633 p = get_part_table(k);
1634
1635 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1636 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1637 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1638}
1639#endif
1640
1641#if defined (__alpha__)
1642
1643#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001644typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001645#endif
1646
1647static void
1648alpha_bootblock_checksum (char *boot)
1649{
Eric Andersendfcb5b02004-01-30 22:54:20 +00001650 uint64_t *dp, sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001651 int i;
1652
Eric Andersendfcb5b02004-01-30 22:54:20 +00001653 dp = (uint64_t *)boot;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001654 sum = 0;
1655 for (i = 0; i < 63; i++)
1656 sum += dp[i];
1657 dp[63] = sum;
1658}
1659#endif /* __alpha__ */
1660
1661#endif /* OSF_LABEL */
1662
1663#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1664static inline unsigned short
1665__swap16(unsigned short x) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001666 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001667}
1668
Eric Andersenacd244a2002-12-11 03:49:33 +00001669static inline uint32_t
1670__swap32(uint32_t x) {
Eric Andersen040f4402003-07-30 08:40:37 +00001671 return (((x & 0xFF) << 24) |
1672 ((x & 0xFF00) << 8) |
1673 ((x & 0xFF0000) >> 8) |
1674 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001675}
1676#endif
1677
1678#ifdef CONFIG_FEATURE_SGI_LABEL
1679/*
1680 *
1681 * fdisksgilabel.c
1682 *
1683 * Copyright (C) Andreas Neuper, Sep 1998.
1684 * This file may be modified and redistributed under
1685 * the terms of the GNU Public License.
1686 *
1687 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1688 * Internationalization
1689 */
1690
1691
1692static int sgi_other_endian;
1693static int debug;
1694static short sgi_volumes=1;
1695
1696/*
1697 * only dealing with free blocks here
1698 */
1699
Eric Andersen040f4402003-07-30 08:40:37 +00001700typedef struct { unsigned int first; unsigned int last; } freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001701static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1702
1703static void
Eric Andersen040f4402003-07-30 08:40:37 +00001704setfreelist(int i, unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001705 freelist[i].first = f;
1706 freelist[i].last = l;
1707}
1708
1709static void
Eric Andersen040f4402003-07-30 08:40:37 +00001710add2freelist(unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001711 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001712 for ( ; i < 17 ; i++)
1713 if (freelist[i].last == 0)
1714 break;
1715 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001716}
1717
1718static void
1719clearfreelist(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00001720 int i;
1721
1722 for (i = 0; i < 17 ; i++)
1723 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001724}
1725
Eric Andersen040f4402003-07-30 08:40:37 +00001726static unsigned int
1727isinfreelist(unsigned int b) {
1728 int i;
1729
1730 for (i = 0; i < 17 ; i++)
1731 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001732 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001733 return 0;
1734}
1735 /* return last vacant block of this stride (never 0). */
1736 /* the '>=' is not quite correct, but simplifies the code */
1737/*
1738 * end of free blocks section
1739 */
1740
1741static const struct systypes sgi_sys_types[] = {
1742/* SGI_VOLHDR */ {"\x00" "SGI volhdr" },
1743/* 0x01 */ {"\x01" "SGI trkrepl" },
1744/* 0x02 */ {"\x02" "SGI secrepl" },
1745/* SGI_SWAP */ {"\x03" "SGI raw" },
1746/* 0x04 */ {"\x04" "SGI bsd" },
1747/* 0x05 */ {"\x05" "SGI sysv" },
1748/* ENTIRE_DISK */ {"\x06" "SGI volume" },
1749/* SGI_EFS */ {"\x07" "SGI efs" },
1750/* 0x08 */ {"\x08" "SGI lvol" },
1751/* 0x09 */ {"\x09" "SGI rlvol" },
1752/* SGI_XFS */ {"\x0a" "SGI xfs" },
1753/* SGI_XFSLOG */ {"\x0b" "SGI xfslog" },
1754/* SGI_XLV */ {"\x0c" "SGI xlv" },
1755/* SGI_XVM */ {"\x0d" "SGI xvm" },
1756/* LINUX_SWAP */ {"\x82" "Linux swap" },
1757/* LINUX_NATIVE */ {"\x83" "Linux native" },
1758/* LINUX_LVM */ {"\x8d" "Linux LVM" },
1759/* LINUX_RAID */ {"\xfd" "Linux RAID" },
1760 { NULL }
1761};
1762
1763
1764static int
1765sgi_get_nsect(void) {
1766 return SGI_SSWAP16(sgilabel->devparam.nsect);
1767}
1768
1769static int
1770sgi_get_ntrks(void) {
1771 return SGI_SSWAP16(sgilabel->devparam.ntrks);
1772}
1773
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001774static void
1775sgi_nolabel(void) {
1776 sgilabel->magic = 0;
1777 sgi_label = 0;
1778 partitions = 4;
1779}
1780
1781static unsigned int
Eric Andersen040f4402003-07-30 08:40:37 +00001782two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001783 int i=0;
1784 unsigned int sum=0;
1785
Eric Andersen040f4402003-07-30 08:40:37 +00001786 size /= sizeof(unsigned int);
1787 for (i = 0; i < size; i++)
1788 sum -= SGI_SSWAP32(base[i]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001789 return sum;
1790}
1791
1792static int
1793check_sgi_label(void) {
1794 if (sizeof(sgilabel) > 512) {
1795 fprintf(stderr,
1796 _("According to MIPS Computer Systems, Inc the "
1797 "Label must not contain more than 512 bytes\n"));
1798 exit(1);
1799 }
1800
1801 if (sgilabel->magic != SGI_LABEL_MAGIC &&
1802 sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1803 sgi_label = 0;
1804 sgi_other_endian = 0;
1805 return 0;
1806 }
1807
1808 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1809 /*
1810 * test for correct checksum
1811 */
Eric Andersen040f4402003-07-30 08:40:37 +00001812 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1813 sizeof(*sgilabel))) {
1814 fprintf(stderr,
1815 _("Detected sgi disklabel with wrong checksum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001816 }
1817 update_units();
1818 sgi_label = 1;
1819 partitions= 16;
1820 sgi_volumes = 15;
1821 return 1;
1822}
1823
Eric Andersen040f4402003-07-30 08:40:37 +00001824static unsigned int
1825sgi_get_start_sector(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001826 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1827}
1828
Eric Andersen040f4402003-07-30 08:40:37 +00001829static unsigned int
1830sgi_get_num_sectors(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001831 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1832}
1833
1834static int
Eric Andersen040f4402003-07-30 08:40:37 +00001835sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001836{
1837 return SGI_SSWAP32(sgilabel->partitions[i].id);
1838}
1839
1840static int
1841sgi_get_bootpartition(void)
1842{
1843 return SGI_SSWAP16(sgilabel->boot_part);
1844}
1845
1846static int
1847sgi_get_swappartition(void)
1848{
1849 return SGI_SSWAP16(sgilabel->swap_part);
1850}
1851
1852static void
Eric Andersen040f4402003-07-30 08:40:37 +00001853sgi_list_table(int xtra) {
Eric Andersen99a75d12003-08-08 20:04:56 +00001854 int i, w, wd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001855 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001856
Eric Andersen040f4402003-07-30 08:40:37 +00001857 if(xtra) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001858 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1859 "%d cylinders, %d physical cylinders\n"
1860 "%d extra sects/cyl, interleave %d:1\n"
1861 "%s\n"
1862 "Units = %s of %d * 512 bytes\n\n"),
1863 disk_device, heads, sectors, cylinders,
1864 SGI_SSWAP16(sgiparam.pcylcount),
1865 SGI_SSWAP16(sgiparam.sparecyl),
1866 SGI_SSWAP16(sgiparam.ilfact),
1867 (char *)sgilabel,
1868 str_units(PLURAL), units_per_sector);
1869 } else {
1870 printf( _("\nDisk %s (SGI disk label): "
1871 "%d heads, %d sectors, %d cylinders\n"
1872 "Units = %s of %d * 512 bytes\n\n"),
1873 disk_device, heads, sectors, cylinders,
1874 str_units(PLURAL), units_per_sector );
1875 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001876
1877 w = strlen(disk_device);
1878 wd = strlen(_("Device"));
1879 if (w < wd)
1880 w = wd;
1881
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001882 printf(_("----- partitions -----\n"
1883 "Pt# %*s Info Start End Sectors Id System\n"),
Eric Andersen99a75d12003-08-08 20:04:56 +00001884 w + 2, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001885 for (i = 0 ; i < partitions; i++) {
1886 if( sgi_get_num_sectors(i) || debug ) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001887 uint32_t start = sgi_get_start_sector(i);
1888 uint32_t len = sgi_get_num_sectors(i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001889 kpi++; /* only count nonempty partitions */
1890 printf(
1891 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1892/* fdisk part number */ i+1,
Eric Andersen99a75d12003-08-08 20:04:56 +00001893/* device */ partname(disk_device, kpi, w+3),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001894/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1895/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1896/* start */ (long) scround(start),
1897/* end */ (long) scround(start+len)-1,
1898/* no odd flag on end */ (long) len,
1899/* type id */ sgi_get_sysid(i),
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001900/* type name */ partition_type(sgi_get_sysid(i)));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001901 }
1902 }
1903 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1904 "----- Directory Entries -----\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00001905 sgilabel->boot_file);
1906 for (i = 0 ; i < sgi_volumes; i++) {
1907 if (sgilabel->directory[i].vol_file_size) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001908 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1909 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
Eric Andersen3496fdc2006-01-30 23:09:20 +00001910 unsigned char*name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001911
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001912 printf(_("%2d: %-10s sector%5u size%8u\n"),
Eric Andersen3496fdc2006-01-30 23:09:20 +00001913 i, (char*)name, (unsigned int) start, (unsigned int) len);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001914 }
1915 }
1916}
1917
1918static void
1919sgi_set_bootpartition( int i )
1920{
1921 sgilabel->boot_part = SGI_SSWAP16(((short)i));
1922}
1923
Eric Andersen040f4402003-07-30 08:40:37 +00001924static unsigned int
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001925sgi_get_lastblock(void) {
1926 return heads * sectors * cylinders;
1927}
1928
1929static void
1930sgi_set_swappartition( int i ) {
1931 sgilabel->swap_part = SGI_SSWAP16(((short)i));
1932}
1933
1934static int
Eric Andersen040f4402003-07-30 08:40:37 +00001935sgi_check_bootfile(const char* aFile) {
1936
1937 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1938 printf(_("\nInvalid Bootfile!\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001939 "\tThe bootfile must be an absolute non-zero pathname,\n"
Eric Andersen040f4402003-07-30 08:40:37 +00001940 "\te.g. \"/unix\" or \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001941 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001942 } else {
1943 if (strlen(aFile) > 16) {
1944 printf(_("\n\tName of Bootfile too long: "
1945 "16 bytes maximum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001946 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001947 } else {
1948 if (aFile[0] != '/') {
1949 printf(_("\n\tBootfile must have a "
1950 "fully qualified pathname.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001951 return 0;
1952 }
Eric Andersen040f4402003-07-30 08:40:37 +00001953 }
1954 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001955 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001956 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1957 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001958 /* filename is correct and did change */
1959 return 1;
1960 }
1961 return 0; /* filename did not change */
1962}
1963
1964static const char *
1965sgi_get_bootfile(void) {
Eric Andersen3496fdc2006-01-30 23:09:20 +00001966 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001967}
1968
1969static void
Eric Andersen040f4402003-07-30 08:40:37 +00001970sgi_set_bootfile(const char* aFile) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001971 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001972
1973 if (sgi_check_bootfile(aFile)) {
1974 while (i < 16) {
1975 if ((aFile[i] != '\n') /* in principle caught again by next line */
1976 && (strlen(aFile) > i))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001977 sgilabel->boot_file[i] = aFile[i];
1978 else
1979 sgilabel->boot_file[i] = 0;
1980 i++;
1981 }
Eric Andersen040f4402003-07-30 08:40:37 +00001982 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001983 }
1984}
1985
1986static void
1987create_sgiinfo(void)
1988{
1989 /* I keep SGI's habit to write the sgilabel to the second block */
Eric Andersen040f4402003-07-30 08:40:37 +00001990 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1991 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
Eric Andersen3496fdc2006-01-30 23:09:20 +00001992 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001993}
1994
Eric Andersen040f4402003-07-30 08:40:37 +00001995static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001996
1997static void
Eric Andersen040f4402003-07-30 08:40:37 +00001998sgi_write_table(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001999 sgilabel->csum = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002000 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002001 (unsigned int*)sgilabel,
Eric Andersen040f4402003-07-30 08:40:37 +00002002 sizeof(*sgilabel)));
2003 assert(two_s_complement_32bit_sum(
2004 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
2005 if (lseek(fd, 0, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002006 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002007 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002008 fdisk_fatal(unable_to_write);
Eric Andersen3496fdc2006-01-30 23:09:20 +00002009 if (! strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002010 /*
Eric Andersen040f4402003-07-30 08:40:37 +00002011 * keep this habit of first writing the "sgilabel".
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002012 * I never tested whether it works without (AN 981002).
2013 */
Eric Andersen040f4402003-07-30 08:40:37 +00002014 sgiinfo *info = fill_sgiinfo();
2015 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
Eric Andersenbbbbcfe2004-03-30 09:33:18 +00002016 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002017 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002018 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002019 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002020 free(info);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002021 }
2022}
2023
2024static int
Eric Andersen040f4402003-07-30 08:40:37 +00002025compare_start(int *x, int *y) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002026 /*
2027 * sort according to start sectors
2028 * and prefers largest partition:
2029 * entry zero is entire disk entry
2030 */
Eric Andersen040f4402003-07-30 08:40:37 +00002031 unsigned int i = *x;
2032 unsigned int j = *y;
2033 unsigned int a = sgi_get_start_sector(i);
2034 unsigned int b = sgi_get_start_sector(j);
2035 unsigned int c = sgi_get_num_sectors(i);
2036 unsigned int d = sgi_get_num_sectors(j);
2037
2038 if (a == b)
2039 return (d > c) ? 1 : (d == c) ? 0 : -1;
2040 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002041}
2042
2043
2044static int
Eric Andersen040f4402003-07-30 08:40:37 +00002045verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002046{
2047 int Index[16]; /* list of valid partitions */
2048 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
Eric Andersen040f4402003-07-30 08:40:37 +00002049 int entire = 0, i = 0;
2050 unsigned int start = 0;
2051 long long gap = 0; /* count unused blocks */
2052 unsigned int lastblock = sgi_get_lastblock();
2053
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002054 clearfreelist();
Eric Andersen040f4402003-07-30 08:40:37 +00002055 for (i=0; i<16; i++) {
2056 if (sgi_get_num_sectors(i) != 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002057 Index[sortcount++]=i;
Eric Andersen040f4402003-07-30 08:40:37 +00002058 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2059 if (entire++ == 1) {
2060 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002061 printf(_("More than one entire disk entry present.\n"));
2062 }
2063 }
2064 }
2065 }
Eric Andersen040f4402003-07-30 08:40:37 +00002066 if (sortcount == 0) {
2067 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002068 printf(_("No partitions defined\n"));
Eric Andersen040f4402003-07-30 08:40:37 +00002069 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002070 }
Eric Andersen040f4402003-07-30 08:40:37 +00002071 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2072 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2073 if ((Index[0] != 10) && verbose)
2074 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2075 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2076 printf(_("The entire disk partition should start "
2077 "at block 0,\n"
2078 "not at diskblock %d.\n"),
2079 sgi_get_start_sector(Index[0]));
2080 if (debug) /* I do not understand how some disks fulfil it */
2081 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2082 printf(_("The entire disk partition is only %d diskblock large,\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002083 "but the disk is %d diskblocks long.\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00002084 sgi_get_num_sectors(Index[0]), lastblock);
2085 lastblock = sgi_get_num_sectors(Index[0]);
2086 } else {
2087 if (verbose)
2088 printf(_("One Partition (#11) should cover the entire disk.\n"));
2089 if (debug>2)
2090 printf("sysid=%d\tpartition=%d\n",
2091 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002092 }
Eric Andersen040f4402003-07-30 08:40:37 +00002093 for (i=1, start=0; i<sortcount; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002094 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
Eric Andersen040f4402003-07-30 08:40:37 +00002095
2096 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2097 if (debug) /* I do not understand how some disks fulfil it */
2098 if (verbose)
2099 printf(_("Partition %d does not start on cylinder boundary.\n"),
2100 Index[i]+1);
2101 }
2102 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2103 if (debug) /* I do not understand how some disks fulfil it */
2104 if (verbose)
2105 printf(_("Partition %d does not end on cylinder boundary.\n"),
2106 Index[i]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002107 }
2108 /* We cannot handle several "entire disk" entries. */
Eric Andersen040f4402003-07-30 08:40:37 +00002109 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2110 if (start > sgi_get_start_sector(Index[i])) {
2111 if (verbose)
2112 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002113 Index[i-1]+1, Index[i]+1,
Eric Andersen040f4402003-07-30 08:40:37 +00002114 start - sgi_get_start_sector(Index[i]));
2115 if (gap > 0) gap = -gap;
2116 if (gap == 0) gap = -1;
2117 }
2118 if (start < sgi_get_start_sector(Index[i])) {
2119 if (verbose)
2120 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2121 sgi_get_start_sector(Index[i]) - start,
2122 start, sgi_get_start_sector(Index[i])-1);
2123 gap += sgi_get_start_sector(Index[i]) - start;
2124 add2freelist(start, sgi_get_start_sector(Index[i]));
2125 }
2126 start = sgi_get_start_sector(Index[i])
2127 + sgi_get_num_sectors(Index[i]);
2128 if (debug > 1) {
2129 if (verbose)
2130 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002131 sgi_get_start_sector(Index[i]),
2132 sgi_get_num_sectors(Index[i]),
Eric Andersen040f4402003-07-30 08:40:37 +00002133 sgi_get_sysid(Index[i]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002134 }
2135 }
Eric Andersen040f4402003-07-30 08:40:37 +00002136 if (start < lastblock) {
2137 if (verbose)
2138 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2139 lastblock - start, start, lastblock-1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002140 gap += lastblock - start;
Eric Andersen040f4402003-07-30 08:40:37 +00002141 add2freelist(start, lastblock);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002142 }
2143 /*
2144 * Done with arithmetics
2145 * Go for details now
2146 */
Eric Andersen040f4402003-07-30 08:40:37 +00002147 if (verbose) {
2148 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2149 printf(_("\nThe boot partition does not exist.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002150 }
Eric Andersen040f4402003-07-30 08:40:37 +00002151 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2152 printf(_("\nThe swap partition does not exist.\n"));
2153 } else {
2154 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2155 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2156 printf(_("\nThe swap partition has no swap type.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002157 }
Eric Andersen040f4402003-07-30 08:40:37 +00002158 if (sgi_check_bootfile("/unix"))
2159 printf(_("\tYou have chosen an unusual boot file name.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002160 }
Eric Andersen040f4402003-07-30 08:40:37 +00002161 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002162}
2163
2164static int
2165sgi_gaps(void) {
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);
2173}
2174
2175static void
2176sgi_change_sysid( int i, int sys )
2177{
2178 if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
2179 {
2180 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2181 return;
2182 }
2183 if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2184 && (sgi_get_start_sector(i)<1) )
2185 {
2186 read_chars(
2187 _("It is highly recommended that the partition at offset 0\n"
2188 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2189 "retrieve from its directory standalone tools like sash and fx.\n"
2190 "Only the \"SGI volume\" entire disk section may violate this.\n"
2191 "Type YES if you are sure about tagging this partition differently.\n"));
2192 if (strcmp (line_ptr, _("YES\n")))
2193 return;
2194 }
2195 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2196}
2197
2198/* returns partition index of first entry marked as entire disk */
2199static int
2200sgi_entire(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00002201 int i;
2202
2203 for(i=0; i<16; i++)
2204 if(sgi_get_sysid(i) == SGI_VOLUME)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002205 return i;
2206 return -1;
2207}
2208
2209static void
Eric Andersen040f4402003-07-30 08:40:37 +00002210sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
2211
2212 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2213 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2214 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002215 set_changed(i);
Eric Andersen040f4402003-07-30 08:40:37 +00002216 if (sgi_gaps() < 0) /* rebuild freelist */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002217 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2218}
2219
2220static void
2221sgi_set_entire(void) {
2222 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002223
2224 for(n=10; n < partitions; n++) {
2225 if(!sgi_get_num_sectors(n) ) {
2226 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002227 break;
2228 }
2229 }
2230}
2231
2232static void
2233sgi_set_volhdr(void)
2234{
2235 int n;
2236 for( n=8; n<partitions; n++ )
2237 {
2238 if(!sgi_get_num_sectors( n ) )
2239 {
2240 /*
2241 * 5 cylinders is an arbitrary value I like
2242 * IRIX 5.3 stored files in the volume header
2243 * (like sash, symmon, fx, ide) with ca. 3200
2244 * sectors.
2245 */
2246 if( heads * sectors * 5 < sgi_get_lastblock() )
2247 sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
2248 break;
2249 }
2250 }
2251}
2252
2253static void
2254sgi_delete_partition( int i )
2255{
2256 sgi_set_partition( i, 0, 0, 0 );
2257}
2258
2259static void
2260sgi_add_partition( int n, int sys )
2261{
2262 char mesg[256];
Eric Andersen040f4402003-07-30 08:40:37 +00002263 unsigned int first=0, last=0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002264
2265 if( n == 10 ) {
2266 sys = SGI_VOLUME;
2267 } else if ( n == 8 ) {
2268 sys = 0;
2269 }
Eric Andersen040f4402003-07-30 08:40:37 +00002270 if(sgi_get_num_sectors(n)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002271 printf(_("Partition %d is already defined. Delete "
2272 "it before re-adding it.\n"), n + 1);
2273 return;
2274 }
Eric Andersen040f4402003-07-30 08:40:37 +00002275 if( (sgi_entire() == -1) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002276 printf(_("Attempting to generate entire disk entry automatically.\n"));
2277 sgi_set_entire();
2278 sgi_set_volhdr();
2279 }
Eric Andersen040f4402003-07-30 08:40:37 +00002280 if( (sgi_gaps() == 0) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002281 printf(_("The entire disk is already covered with partitions.\n"));
2282 return;
2283 }
Eric Andersen040f4402003-07-30 08:40:37 +00002284 if(sgi_gaps() < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002285 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2286 return;
2287 }
2288 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2289 for(;;) {
2290 if(sys == SGI_VOLUME) {
2291 last = sgi_get_lastblock();
2292 first = read_int(0, 0, last-1, 0, mesg);
2293 if( first != 0 ) {
2294 printf(_("It is highly recommended that eleventh partition\n"
2295 "covers the entire disk and is of type `SGI volume'\n"));
2296 }
2297 } else {
2298 first = freelist[0].first;
2299 last = freelist[0].last;
2300 first = read_int(scround(first), scround(first), scround(last)-1,
2301 0, mesg);
2302 }
2303 if (display_in_cyl_units)
2304 first *= units_per_sector;
2305 else
2306 first = first; /* align to cylinder if you know how ... */
2307 if( !last )
2308 last = isinfreelist(first);
2309 if( last == 0 ) {
2310 printf(_("You will get a partition overlap on the disk. "
2311 "Fix it first!\n"));
2312 } else
2313 break;
2314 }
2315 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2316 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2317 scround(first), mesg)+1;
2318 if (display_in_cyl_units)
2319 last *= units_per_sector;
2320 else
2321 last = last; /* align to cylinder if You know how ... */
2322 if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
2323 printf(_("It is highly recommended that eleventh partition\n"
2324 "covers the entire disk and is of type `SGI volume'\n"));
2325 sgi_set_partition( n, first, last-first, sys );
2326}
2327
Eric Andersen040f4402003-07-30 08:40:37 +00002328#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002329static void
2330create_sgilabel(void)
2331{
2332 struct hd_geometry geometry;
Eric Andersen040f4402003-07-30 08:40:37 +00002333 struct {
2334 unsigned int start;
2335 unsigned int nsect;
2336 int sysid;
2337 } old[4];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002338 int i=0;
Eric Andersen040f4402003-07-30 08:40:37 +00002339 long longsectors; /* the number of sectors on the device */
2340 int res; /* the result from the ioctl */
2341 int sec_fac; /* the sector factor */
2342
2343 sec_fac = sector_size / 512; /* determine the sector factor */
2344
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002345 fprintf( stderr,
2346 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2347 "until you decide to write them. After that, of course, the previous\n"
2348 "content will be unrecoverably lost.\n\n"));
2349
2350 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
Eric Andersen040f4402003-07-30 08:40:37 +00002351 res = ioctl(fd, BLKGETSIZE, &longsectors);
2352 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002353 heads = geometry.heads;
2354 sectors = geometry.sectors;
Eric Andersen040f4402003-07-30 08:40:37 +00002355 if (res == 0) {
2356 /* the get device size ioctl was successful */
2357 cylinders = longsectors / (heads * sectors);
2358 cylinders /= sec_fac;
2359 } else {
2360 /* otherwise print error and use truncated version */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002361 cylinders = geometry.cylinders;
Eric Andersen040f4402003-07-30 08:40:37 +00002362 fprintf(stderr,
2363 _("Warning: BLKGETSIZE ioctl failed on %s. "
2364 "Using geometry cylinder value of %d.\n"
2365 "This value may be truncated for devices"
2366 " > 33.8 GB.\n"), disk_device, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002367 }
Eric Andersen040f4402003-07-30 08:40:37 +00002368 }
2369 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002370 old[i].sysid = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002371 if(valid_part_table_flag(MBRbuffer)) {
2372 if(get_part_table(i)->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002373 old[i].sysid = get_part_table(i)->sys_ind;
Eric Andersen040f4402003-07-30 08:40:37 +00002374 old[i].start = get_start_sect(get_part_table(i));
2375 old[i].nsect = get_nr_sects(get_part_table(i));
2376 printf(_("Trying to keep parameters of partition %d.\n"), i);
2377 if (debug)
2378 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2379 old[i].sysid, old[i].start, old[i].nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002380 }
2381 }
2382 }
Eric Andersen040f4402003-07-30 08:40:37 +00002383
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002384 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2385 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2386 sgilabel->boot_part = SGI_SSWAP16(0);
2387 sgilabel->swap_part = SGI_SSWAP16(1);
2388
2389 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2390 memset(sgilabel->boot_file, 0, 16);
Eric Andersen3496fdc2006-01-30 23:09:20 +00002391 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002392
2393 sgilabel->devparam.skew = (0);
2394 sgilabel->devparam.gap1 = (0);
2395 sgilabel->devparam.gap2 = (0);
2396 sgilabel->devparam.sparecyl = (0);
2397 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2398 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2399 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
2400 /* tracks/cylinder (heads) */
2401 sgilabel->devparam.cmd_tag_queue_depth = (0);
2402 sgilabel->devparam.unused0 = (0);
2403 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2404 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
2405 /* sectors/track */
2406 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2407 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2408 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
2409 IGNORE_ERRORS|RESEEK);
2410 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2411 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2412 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2413 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2414 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2415 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2416 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2417 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2418 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2419 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2420 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2421 sgi_label = 1;
2422 partitions = 16;
2423 sgi_volumes = 15;
2424 sgi_set_entire();
2425 sgi_set_volhdr();
Eric Andersen040f4402003-07-30 08:40:37 +00002426 for (i = 0; i < 4; i++) {
2427 if(old[i].sysid) {
2428 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002429 }
2430 }
2431}
2432
2433static void
2434sgi_set_xcyl(void)
2435{
2436 /* do nothing in the beginning */
2437}
Eric Andersen040f4402003-07-30 08:40:37 +00002438#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002439
2440/* _____________________________________________________________
2441 */
2442
Eric Andersen040f4402003-07-30 08:40:37 +00002443static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002444fill_sgiinfo(void)
2445{
Eric Andersen040f4402003-07-30 08:40:37 +00002446 sgiinfo *info = calloc(1, sizeof(sgiinfo));
2447
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002448 info->magic=SGI_SSWAP32(SGI_INFO_MAGIC);
2449 info->b1=SGI_SSWAP32(-1);
2450 info->b2=SGI_SSWAP16(-1);
2451 info->b3=SGI_SSWAP16(1);
2452 /* You may want to replace this string !!!!!!! */
Eric Andersen3496fdc2006-01-30 23:09:20 +00002453 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2454 strcpy( (char*)info->serial, "0000" );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002455 info->check1816 = SGI_SSWAP16(18*256 +16 );
Eric Andersen3496fdc2006-01-30 23:09:20 +00002456 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002457 return info;
2458}
2459#endif /* SGI_LABEL */
2460
2461
2462#ifdef CONFIG_FEATURE_SUN_LABEL
2463/*
2464 * fdisksunlabel.c
2465 *
2466 * I think this is mostly, or entirely, due to
2467 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2468 *
2469 * Merged with fdisk for other architectures, aeb, June 1998.
2470 *
2471 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2472 * Internationalization
2473 */
2474
2475
2476static int sun_other_endian;
2477static int scsi_disk;
2478static int floppy;
2479
2480#ifndef IDE0_MAJOR
2481#define IDE0_MAJOR 3
2482#endif
2483#ifndef IDE1_MAJOR
2484#define IDE1_MAJOR 22
2485#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002486
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002487static void guess_device_type(void) {
2488 struct stat bootstat;
2489
2490 if (fstat (fd, &bootstat) < 0) {
2491 scsi_disk = 0;
2492 floppy = 0;
2493 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002494 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2495 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002496 scsi_disk = 0;
2497 floppy = 0;
2498 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002499 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002500 scsi_disk = 0;
2501 floppy = 1;
2502 } else {
2503 scsi_disk = 1;
2504 floppy = 0;
2505 }
2506}
2507
2508static const struct systypes sun_sys_types[] = {
2509/* 0 */ {"\x00" "Empty" },
2510/* 1 */ {"\x01" "Boot" },
2511/* 2 */ {"\x02" "SunOS root" },
2512/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
2513/* 4 */ {"\x04" "SunOS usr" },
2514/* WHOLE_DISK */ {"\x05" "Whole disk" },
2515/* 6 */ {"\x06" "SunOS stand" },
2516/* 7 */ {"\x07" "SunOS var" },
2517/* 8 */ {"\x08" "SunOS home" },
2518/* LINUX_SWAP */ {"\x82" "Linux swap" },
2519/* LINUX_NATIVE */ {"\x83" "Linux native" },
2520/* 0x8e */ {"\x8e" "Linux LVM" },
2521/* New (2.2.x) raid partition with autodetect using persistent superblock */
2522/* 0xfd */ {"\xfd" "Linux raid autodetect" },
2523 { NULL }
2524};
2525
2526
2527static void
2528set_sun_partition(int i, uint start, uint stop, int sysid) {
2529 sunlabel->infos[i].id = sysid;
2530 sunlabel->partitions[i].start_cylinder =
2531 SUN_SSWAP32(start / (heads * sectors));
2532 sunlabel->partitions[i].num_sectors =
2533 SUN_SSWAP32(stop - start);
2534 set_changed(i);
2535}
2536
2537static void
2538sun_nolabel(void) {
2539 sun_label = 0;
2540 sunlabel->magic = 0;
2541 partitions = 4;
2542}
2543
2544static int
2545check_sun_label(void) {
2546 unsigned short *ush;
2547 int csum;
2548
2549 if (sunlabel->magic != SUN_LABEL_MAGIC &&
2550 sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2551 sun_label = 0;
2552 sun_other_endian = 0;
2553 return 0;
2554 }
2555 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2556 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2557 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2558 if (csum) {
2559 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2560 "Probably you'll have to set all the values,\n"
2561 "e.g. heads, sectors, cylinders and partitions\n"
2562 "or force a fresh label (s command in main menu)\n"));
2563 } else {
2564 heads = SUN_SSWAP16(sunlabel->ntrks);
2565 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2566 sectors = SUN_SSWAP16(sunlabel->nsect);
2567 }
2568 update_units();
2569 sun_label = 1;
2570 partitions = 8;
2571 return 1;
2572}
2573
2574static const struct sun_predefined_drives {
2575 const char *vendor;
2576 const char *model;
2577 unsigned short sparecyl;
2578 unsigned short ncyl;
2579 unsigned short nacyl;
2580 unsigned short pcylcount;
2581 unsigned short ntrks;
2582 unsigned short nsect;
2583 unsigned short rspeed;
2584} sun_drives[] = {
2585{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2586{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2587{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2588{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2589{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2590{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2591{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2592{"","SUN0104",1,974,2,1019,6,35,3662},
2593{"","SUN0207",4,1254,2,1272,9,36,3600},
2594{"","SUN0327",3,1545,2,1549,9,46,3600},
2595{"","SUN0340",0,1538,2,1544,6,72,4200},
2596{"","SUN0424",2,1151,2,2500,9,80,4400},
2597{"","SUN0535",0,1866,2,2500,7,80,5400},
2598{"","SUN0669",5,1614,2,1632,15,54,3600},
2599{"","SUN1.0G",5,1703,2,1931,15,80,3597},
2600{"","SUN1.05",0,2036,2,2038,14,72,5400},
2601{"","SUN1.3G",6,1965,2,3500,17,80,5400},
2602{"","SUN2.1G",0,2733,2,3500,19,80,5400},
2603{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2604};
2605
2606static const struct sun_predefined_drives *
2607sun_autoconfigure_scsi(void) {
2608 const struct sun_predefined_drives *p = NULL;
2609
2610#ifdef SCSI_IOCTL_GET_IDLUN
2611 unsigned int id[2];
2612 char buffer[2048];
2613 char buffer2[2048];
2614 FILE *pfd;
2615 char *vendor;
2616 char *model;
2617 char *q;
2618 int i;
2619
2620 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2621 sprintf(buffer,
2622 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2623#if 0
2624 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2625#else
2626 /* This is very wrong (works only if you have one HBA),
2627 but I haven't found a way how to get hostno
2628 from the current kernel */
2629 0,
2630#endif
2631 (id[0]>>16)&0xff,
2632 id[0]&0xff,
2633 (id[0]>>8)&0xff);
2634 pfd = fopen("/proc/scsi/scsi","r");
2635 if (pfd) {
2636 while (fgets(buffer2,2048,pfd)) {
2637 if (!strcmp(buffer, buffer2)) {
2638 if (fgets(buffer2,2048,pfd)) {
2639 q = strstr(buffer2,"Vendor: ");
2640 if (q) {
2641 q += 8;
2642 vendor = q;
2643 q = strstr(q," ");
2644 *q++ = 0; /* truncate vendor name */
2645 q = strstr(q,"Model: ");
2646 if (q) {
2647 *q = 0;
2648 q += 7;
2649 model = q;
2650 q = strstr(q," Rev: ");
2651 if (q) {
2652 *q = 0;
2653 for (i = 0; i < SIZE(sun_drives); i++) {
2654 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2655 continue;
2656 if (!strstr(model, sun_drives[i].model))
2657 continue;
2658 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2659 p = sun_drives + i;
2660 break;
2661 }
2662 }
2663 }
2664 }
2665 }
2666 break;
2667 }
2668 }
2669 fclose(pfd);
2670 }
2671 }
2672#endif
2673 return p;
2674}
2675
2676static void create_sunlabel(void)
2677{
2678 struct hd_geometry geometry;
2679 unsigned int ndiv;
2680 int i;
2681 unsigned char c;
2682 const struct sun_predefined_drives *p = NULL;
2683
2684 fprintf(stderr,
2685 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2686 "until you decide to write them. After that, of course, the previous\n"
2687 "content won't be recoverable.\n\n"));
2688#if BYTE_ORDER == LITTLE_ENDIAN
2689 sun_other_endian = 1;
2690#else
2691 sun_other_endian = 0;
2692#endif
2693 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2694 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2695 if (!floppy) {
2696 puts(_("Drive type\n"
2697 " ? auto configure\n"
2698 " 0 custom (with hardware detected defaults)"));
2699 for (i = 0; i < SIZE(sun_drives); i++) {
2700 printf(" %c %s%s%s\n",
2701 i + 'a', sun_drives[i].vendor,
2702 (*sun_drives[i].vendor) ? " " : "",
2703 sun_drives[i].model);
2704 }
2705 for (;;) {
2706 c = read_char(_("Select type (? for auto, 0 for custom): "));
2707 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2708 p = sun_drives + c - 'a';
2709 break;
2710 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2711 p = sun_drives + c - 'A';
2712 break;
2713 } else if (c == '0') {
2714 break;
2715 } else if (c == '?' && scsi_disk) {
2716 p = sun_autoconfigure_scsi();
2717 if (!p)
2718 printf(_("Autoconfigure failed.\n"));
2719 else
2720 break;
2721 }
2722 }
2723 }
2724 if (!p || floppy) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002725 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002726 heads = geometry.heads;
2727 sectors = geometry.sectors;
2728 cylinders = geometry.cylinders;
2729 } else {
2730 heads = 0;
2731 sectors = 0;
2732 cylinders = 0;
2733 }
2734 if (floppy) {
2735 sunlabel->nacyl = 0;
2736 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2737 sunlabel->rspeed = SUN_SSWAP16(300);
2738 sunlabel->ilfact = SUN_SSWAP16(1);
2739 sunlabel->sparecyl = 0;
2740 } else {
2741 heads = read_int(1,heads,1024,0,_("Heads"));
2742 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2743 if (cylinders)
2744 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2745 else
2746 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2747 sunlabel->nacyl =
2748 SUN_SSWAP16(read_int(0,2,65535,0,
2749 _("Alternate cylinders")));
2750 sunlabel->pcylcount =
2751 SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl),
2752 65535,0,_("Physical cylinders")));
2753 sunlabel->rspeed =
2754 SUN_SSWAP16(read_int(1,5400,100000,0,
2755 _("Rotation speed (rpm)")));
2756 sunlabel->ilfact =
2757 SUN_SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
2758 sunlabel->sparecyl =
2759 SUN_SSWAP16(read_int(0,0,sectors,0,
2760 _("Extra sectors per cylinder")));
2761 }
2762 } else {
2763 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2764 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2765 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2766 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2767 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2768 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2769 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2770 sunlabel->ilfact = SUN_SSWAP16(1);
2771 cylinders = p->ncyl;
2772 heads = p->ntrks;
2773 sectors = p->nsect;
2774 puts(_("You may change all the disk params from the x menu"));
2775 }
2776
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002777 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002778 "%s%s%s cyl %d alt %d hd %d sec %d",
2779 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2780 p ? p->model
2781 : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2782 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2783
2784 sunlabel->ntrks = SUN_SSWAP16(heads);
2785 sunlabel->nsect = SUN_SSWAP16(sectors);
2786 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2787 if (floppy)
2788 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2789 else {
2790 if (cylinders * heads * sectors >= 150 * 2048) {
2791 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2792 } else
2793 ndiv = cylinders * 2 / 3;
2794 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2795 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2796 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2797 }
2798 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2799 {
2800 unsigned short *ush = (unsigned short *)sunlabel;
2801 unsigned short csum = 0;
2802 while(ush < (unsigned short *)(&sunlabel->csum))
2803 csum ^= *ush++;
2804 sunlabel->csum = csum;
2805 }
2806
2807 set_all_unchanged();
2808 set_changed(0);
2809 get_boot(create_empty_sun);
2810}
2811
2812static void
2813toggle_sunflags(int i, unsigned char mask) {
2814 if (sunlabel->infos[i].flags & mask)
2815 sunlabel->infos[i].flags &= ~mask;
2816 else sunlabel->infos[i].flags |= mask;
2817 set_changed(i);
2818}
2819
2820static void
2821fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) {
2822 int i, continuous = 1;
2823 *start = 0; *stop = cylinders * heads * sectors;
2824 for (i = 0; i < partitions; i++) {
2825 if (sunlabel->partitions[i].num_sectors
2826 && sunlabel->infos[i].id
2827 && sunlabel->infos[i].id != WHOLE_DISK) {
2828 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2829 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2830 if (continuous) {
2831 if (starts[i] == *start)
2832 *start += lens[i];
2833 else if (starts[i] + lens[i] >= *stop)
2834 *stop = starts[i];
2835 else
2836 continuous = 0;
2837 /* There will be probably more gaps
2838 than one, so lets check afterwards */
2839 }
2840 } else {
2841 starts[i] = 0;
2842 lens[i] = 0;
2843 }
2844 }
2845}
2846
2847static uint *verify_sun_starts;
2848
2849static int
2850verify_sun_cmp(int *a, int *b) {
2851 if (*a == -1) return 1;
2852 if (*b == -1) return -1;
2853 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2854 return -1;
2855}
2856
2857static void
2858verify_sun(void) {
2859 uint starts[8], lens[8], start, stop;
2860 int i,j,k,starto,endo;
2861 int array[8];
2862
2863 verify_sun_starts = starts;
2864 fetch_sun(starts,lens,&start,&stop);
2865 for (k = 0; k < 7; k++) {
2866 for (i = 0; i < 8; i++) {
2867 if (k && (lens[i] % (heads * sectors))) {
2868 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2869 }
2870 if (lens[i]) {
2871 for (j = 0; j < i; j++)
2872 if (lens[j]) {
2873 if (starts[j] == starts[i]+lens[i]) {
2874 starts[j] = starts[i]; lens[j] += lens[i];
2875 lens[i] = 0;
2876 } else if (starts[i] == starts[j]+lens[j]){
2877 lens[j] += lens[i];
2878 lens[i] = 0;
2879 } else if (!k) {
2880 if (starts[i] < starts[j]+lens[j] &&
2881 starts[j] < starts[i]+lens[i]) {
2882 starto = starts[i];
2883 if (starts[j] > starto)
2884 starto = starts[j];
2885 endo = starts[i]+lens[i];
2886 if (starts[j]+lens[j] < endo)
2887 endo = starts[j]+lens[j];
2888 printf(_("Partition %d overlaps with others in "
2889 "sectors %d-%d\n"), i+1, starto, endo);
2890 }
2891 }
2892 }
2893 }
2894 }
2895 }
2896 for (i = 0; i < 8; i++) {
2897 if (lens[i])
2898 array[i] = i;
2899 else
2900 array[i] = -1;
2901 }
2902 qsort(array,SIZE(array),sizeof(array[0]),
2903 (int (*)(const void *,const void *)) verify_sun_cmp);
2904 if (array[0] == -1) {
2905 printf(_("No partitions defined\n"));
2906 return;
2907 }
2908 stop = cylinders * heads * sectors;
2909 if (starts[array[0]])
2910 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2911 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2912 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2913 }
2914 start = starts[array[i]]+lens[array[i]];
2915 if (start < stop)
2916 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2917}
2918
2919static void
2920add_sun_partition(int n, int sys) {
2921 uint start, stop, stop2;
2922 uint starts[8], lens[8];
2923 int whole_disk = 0;
2924
2925 char mesg[256];
2926 int i, first, last;
2927
2928 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2929 printf(_("Partition %d is already defined. Delete "
2930 "it before re-adding it.\n"), n + 1);
2931 return;
2932 }
2933
2934 fetch_sun(starts,lens,&start,&stop);
2935 if (stop <= start) {
2936 if (n == 2)
2937 whole_disk = 1;
2938 else {
2939 printf(_("Other partitions already cover the whole disk.\nDelete "
2940 "some/shrink them before retry.\n"));
2941 return;
2942 }
2943 }
2944 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2945 for (;;) {
2946 if (whole_disk)
2947 first = read_int(0, 0, 0, 0, mesg);
2948 else
2949 first = read_int(scround(start), scround(stop)+1,
2950 scround(stop), 0, mesg);
2951 if (display_in_cyl_units)
2952 first *= units_per_sector;
2953 else
2954 /* Starting sector has to be properly aligned */
2955 first = (first + heads * sectors - 1) / (heads * sectors);
2956 if (n == 2 && first != 0)
2957 printf ("\
2958It is highly recommended that the third partition covers the whole disk\n\
2959and is of type `Whole disk'\n");
2960 /* ewt asks to add: "don't start a partition at cyl 0"
2961 However, edmundo@rano.demon.co.uk writes:
2962 "In addition to having a Sun partition table, to be able to
2963 boot from the disc, the first partition, /dev/sdX1, must
2964 start at cylinder 0. This means that /dev/sdX1 contains
2965 the partition table and the boot block, as these are the
2966 first two sectors of the disc. Therefore you must be
2967 careful what you use /dev/sdX1 for. In particular, you must
2968 not use a partition starting at cylinder 0 for Linux swap,
2969 as that would overwrite the partition table and the boot
2970 block. You may, however, use such a partition for a UFS
2971 or EXT2 file system, as these file systems leave the first
2972 1024 bytes undisturbed. */
2973 /* On the other hand, one should not use partitions
2974 starting at block 0 in an md, or the label will
2975 be trashed. */
2976 for (i = 0; i < partitions; i++)
2977 if (lens[i] && starts[i] <= first
2978 && starts[i] + lens[i] > first)
2979 break;
2980 if (i < partitions && !whole_disk) {
2981 if (n == 2 && !first) {
2982 whole_disk = 1;
2983 break;
2984 }
2985 printf(_("Sector %d is already allocated\n"), first);
2986 } else
2987 break;
2988 }
2989 stop = cylinders * heads * sectors;
2990 stop2 = stop;
2991 for (i = 0; i < partitions; i++) {
2992 if (starts[i] > first && starts[i] < stop)
2993 stop = starts[i];
2994 }
2995 snprintf(mesg, sizeof(mesg),
2996 _("Last %s or +size or +sizeM or +sizeK"),
2997 str_units(SINGULAR));
2998 if (whole_disk)
2999 last = read_int(scround(stop2), scround(stop2), scround(stop2),
3000 0, mesg);
3001 else if (n == 2 && !first)
3002 last = read_int(scround(first), scround(stop2), scround(stop2),
3003 scround(first), mesg);
3004 else
3005 last = read_int(scround(first), scround(stop), scround(stop),
3006 scround(first), mesg);
3007 if (display_in_cyl_units)
3008 last *= units_per_sector;
3009 if (n == 2 && !first) {
3010 if (last >= stop2) {
3011 whole_disk = 1;
3012 last = stop2;
3013 } else if (last > stop) {
3014 printf (
3015 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
3016 "%d %s covers some other partition. Your entry has been changed\n"
3017 "to %d %s\n"),
3018 scround(last), str_units(SINGULAR),
3019 scround(stop), str_units(SINGULAR));
3020 last = stop;
3021 }
3022 } else if (!whole_disk && last > stop)
3023 last = stop;
3024
3025 if (whole_disk) sys = WHOLE_DISK;
3026 set_sun_partition(n, first, last, sys);
3027}
3028
3029static void
3030sun_delete_partition(int i) {
Eric Andersen040f4402003-07-30 08:40:37 +00003031 unsigned int nsec;
3032
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003033 if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
3034 !sunlabel->partitions[i].start_cylinder &&
Eric Andersen040f4402003-07-30 08:40:37 +00003035 (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003036 == heads * sectors * cylinders)
3037 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3038 "consider leaving this\n"
3039 "partition as Whole disk (5), starting at 0, with %u "
Eric Andersen040f4402003-07-30 08:40:37 +00003040 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003041 sunlabel->infos[i].id = 0;
3042 sunlabel->partitions[i].num_sectors = 0;
3043}
3044
3045static void
3046sun_change_sysid(int i, int sys) {
3047 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3048 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;
3056 }
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
3073sun_list_table(int xtra) {
3074 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003075
3076 w = strlen(disk_device);
3077 if (xtra)
3078 printf(
3079 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3080 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3081 "%d extra sects/cyl, interleave %d:1\n"
3082 "%s\n"
3083 "Units = %s of %d * 512 bytes\n\n"),
3084 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3085 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3086 SUN_SSWAP16(sunlabel->pcylcount),
3087 SUN_SSWAP16(sunlabel->sparecyl),
3088 SUN_SSWAP16(sunlabel->ilfact),
3089 (char *)sunlabel,
3090 str_units(PLURAL), units_per_sector);
3091 else
3092 printf(
3093 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3094 "Units = %s of %d * 512 bytes\n\n"),
3095 disk_device, heads, sectors, cylinders,
3096 str_units(PLURAL), units_per_sector);
3097
3098 printf(_("%*s Flag Start End Blocks Id System\n"),
3099 w + 1, _("Device"));
3100 for (i = 0 ; i < partitions; i++) {
3101 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003102 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3103 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003104 printf(
3105 "%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3106/* device */ partname(disk_device, i+1, w),
3107/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
3108 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3109/* start */ (long) scround(start),
3110/* end */ (long) scround(start+len),
3111/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
3112/* type id */ sunlabel->infos[i].id,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003113/* type name */ partition_type(sunlabel->infos[i].id));
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
3121sun_set_alt_cyl(void) {
3122 sunlabel->nacyl =
3123 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3124 _("Number of alternate cylinders")));
3125}
3126
3127static void
3128sun_set_ncyl(int cyl) {
3129 sunlabel->ncyl = SUN_SSWAP16(cyl);
3130}
3131
3132static void
3133sun_set_xcyl(void) {
3134 sunlabel->sparecyl =
3135 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3136 _("Extra sectors per cylinder")));
3137}
3138
3139static void
3140sun_set_ilfact(void) {
3141 sunlabel->ilfact =
3142 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3143 _("Interleave factor")));
3144}
3145
3146static void
3147sun_set_rspeed(void) {
3148 sunlabel->rspeed =
3149 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3150 _("Rotation speed (rpm)")));
3151}
3152
3153static void
3154sun_set_pcylcount(void) {
3155 sunlabel->pcylcount =
3156 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3157 _("Number of physical cylinders")));
3158}
Eric Andersen040f4402003-07-30 08:40:37 +00003159#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003160
3161static void
3162sun_write_table(void) {
3163 unsigned short *ush = (unsigned short *)sunlabel;
3164 unsigned short csum = 0;
3165
3166 while(ush < (unsigned short *)(&sunlabel->csum))
3167 csum ^= *ush++;
3168 sunlabel->csum = csum;
3169 if (lseek(fd, 0, SEEK_SET) < 0)
3170 fdisk_fatal(unable_to_seek);
3171 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3172 fdisk_fatal(unable_to_write);
3173}
3174#endif /* SUN_LABEL */
3175
3176/* DOS partition types */
3177
3178static const struct systypes i386_sys_types[] = {
3179 {"\x00" "Empty"},
3180 {"\x01" "FAT12"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003181 {"\x04" "FAT16 <32M"},
3182 {"\x05" "Extended"}, /* DOS 3.3+ extended partition */
3183 {"\x06" "FAT16"}, /* DOS 16-bit >=32M */
3184 {"\x07" "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003185 {"\x0a" "OS/2 Boot Manager"},/* OS/2 Boot Manager */
3186 {"\x0b" "Win95 FAT32"},
3187 {"\x0c" "Win95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
3188 {"\x0e" "Win95 FAT16 (LBA)"},
3189 {"\x0f" "Win95 Ext'd (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003190 {"\x11" "Hidden FAT12"},
3191 {"\x12" "Compaq diagnostics"},
3192 {"\x14" "Hidden FAT16 <32M"},
3193 {"\x16" "Hidden FAT16"},
3194 {"\x17" "Hidden HPFS/NTFS"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003195 {"\x1b" "Hidden Win95 FAT32"},
3196 {"\x1c" "Hidden Win95 FAT32 (LBA)"},
3197 {"\x1e" "Hidden Win95 FAT16 (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003198 {"\x3c" "PartitionMagic recovery"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003199 {"\x41" "PPC PReP Boot"},
3200 {"\x42" "SFS"},
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003201 {"\x63" "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3202 {"\x80" "Old Minix"}, /* Minix 1.4a and earlier */
3203 {"\x81" "Minix / old Linux"},/* Minix 1.4b and later */
3204 {"\x82" "Linux swap"}, /* also Solaris */
3205 {"\x83" "Linux"},
3206 {"\x84" "OS/2 hidden C: drive"},
3207 {"\x85" "Linux extended"},
3208 {"\x86" "NTFS volume set"},
3209 {"\x87" "NTFS volume set"},
3210 {"\x8e" "Linux LVM"},
3211 {"\x9f" "BSD/OS"}, /* BSDI */
3212 {"\xa0" "IBM Thinkpad hibernation"},
3213 {"\xa5" "FreeBSD"}, /* various BSD flavours */
3214 {"\xa6" "OpenBSD"},
3215 {"\xa8" "Darwin UFS"},
3216 {"\xa9" "NetBSD"},
3217 {"\xab" "Darwin boot"},
3218 {"\xb7" "BSDI fs"},
3219 {"\xb8" "BSDI swap"},
3220 {"\xbe" "Solaris boot"},
3221 {"\xeb" "BeOS fs"},
3222 {"\xee" "EFI GPT"}, /* Intel EFI GUID Partition Table */
3223 {"\xef" "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
3224 {"\xf0" "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
3225 {"\xf2" "DOS secondary"}, /* DOS 3.3+ secondary */
3226 {"\xfd" "Linux raid autodetect"},/* New (2.2.x) raid partition with
3227 autodetect using persistent
3228 superblock */
3229#ifdef CONFIG_WEIRD_PARTITION_TYPES
3230 {"\x02" "XENIX root"},
3231 {"\x03" "XENIX usr"},
3232 {"\x08" "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3233 {"\x09" "AIX bootable"}, /* AIX data or Coherent */
3234 {"\x10" "OPUS"},
3235 {"\x18" "AST SmartSleep"},
3236 {"\x24" "NEC DOS"},
3237 {"\x39" "Plan 9"},
3238 {"\x40" "Venix 80286"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003239 {"\x4d" "QNX4.x"},
3240 {"\x4e" "QNX4.x 2nd part"},
3241 {"\x4f" "QNX4.x 3rd part"},
3242 {"\x50" "OnTrack DM"},
3243 {"\x51" "OnTrack DM6 Aux1"}, /* (or Novell) */
3244 {"\x52" "CP/M"}, /* CP/M or Microport SysV/AT */
3245 {"\x53" "OnTrack DM6 Aux3"},
3246 {"\x54" "OnTrackDM6"},
3247 {"\x55" "EZ-Drive"},
3248 {"\x56" "Golden Bow"},
3249 {"\x5c" "Priam Edisk"},
3250 {"\x61" "SpeedStor"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003251 {"\x64" "Novell Netware 286"},
3252 {"\x65" "Novell Netware 386"},
3253 {"\x70" "DiskSecure Multi-Boot"},
3254 {"\x75" "PC/IX"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003255 {"\x93" "Amoeba"},
3256 {"\x94" "Amoeba BBT"}, /* (bad block table) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003257 {"\xa7" "NeXTSTEP"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003258 {"\xbb" "Boot Wizard hidden"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003259 {"\xc1" "DRDOS/sec (FAT-12)"},
3260 {"\xc4" "DRDOS/sec (FAT-16 < 32M)"},
3261 {"\xc6" "DRDOS/sec (FAT-16)"},
3262 {"\xc7" "Syrinx"},
3263 {"\xda" "Non-FS data"},
3264 {"\xdb" "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
3265 Concurrent DOS or CTOS */
3266 {"\xde" "Dell Utility"}, /* Dell PowerEdge Server utilities */
3267 {"\xdf" "BootIt"}, /* BootIt EMBRM */
3268 {"\xe1" "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
3269 extended partition */
3270 {"\xe3" "DOS R/O"}, /* DOS R/O or SpeedStor */
3271 {"\xe4" "SpeedStor"}, /* SpeedStor 16-bit FAT extended
3272 partition < 1024 cyl. */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003273 {"\xf1" "SpeedStor"},
3274 {"\xf4" "SpeedStor"}, /* SpeedStor large partition */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003275 {"\xfe" "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
3276 {"\xff" "BBT"}, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003277#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003278 { 0 }
3279};
3280
3281
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003282
3283/* A valid partition table sector ends in 0x55 0xaa */
3284static unsigned int
3285part_table_flag(const char *b) {
3286 return ((uint) b[510]) + (((uint) b[511]) << 8);
3287}
3288
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003289
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003290#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003291static void
3292write_part_table_flag(char *b) {
3293 b[510] = 0x55;
3294 b[511] = 0xaa;
3295}
3296
3297/* start_sect and nr_sects are stored little endian on all machines */
3298/* moreover, they are not aligned correctly */
3299static void
3300store4_little_endian(unsigned char *cp, unsigned int val) {
3301 cp[0] = (val & 0xff);
3302 cp[1] = ((val >> 8) & 0xff);
3303 cp[2] = ((val >> 16) & 0xff);
3304 cp[3] = ((val >> 24) & 0xff);
3305}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003306#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003307
3308static unsigned int
3309read4_little_endian(const unsigned char *cp) {
3310 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3311 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3312}
3313
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003314#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003315static void
3316set_start_sect(struct partition *p, unsigned int start_sect) {
3317 store4_little_endian(p->start4, start_sect);
3318}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003319#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003320
Eric Andersend9261492004-06-28 23:50:31 +00003321static int32_t
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003322get_start_sect(const struct partition *p) {
3323 return read4_little_endian(p->start4);
3324}
3325
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003326#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003327static void
Eric Andersend9261492004-06-28 23:50:31 +00003328set_nr_sects(struct partition *p, int32_t nr_sects) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003329 store4_little_endian(p->size4, nr_sects);
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
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003334get_nr_sects(const struct partition *p) {
3335 return read4_little_endian(p->size4);
3336}
3337
3338/* normally O_RDWR, -l option gives O_RDONLY */
3339static int type_open = O_RDWR;
3340
3341
3342static int ext_index, /* the prime extended partition */
3343 listing, /* no aborts for fdisk -l */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003344 dos_compatible_flag = ~0;
3345#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3346static int dos_changed;
3347static int nowarn; /* no warnings for fdisk -l/-s */
3348#endif
3349
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003350
3351
3352static uint user_cylinders, user_heads, user_sectors;
3353static uint pt_heads, pt_sectors;
3354static uint kern_heads, kern_sectors;
3355
Eric Andersend9261492004-06-28 23:50:31 +00003356static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003357
Eric Andersen040f4402003-07-30 08:40:37 +00003358static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003359
3360
3361static jmp_buf listingbuf;
3362
3363static void fdisk_fatal(enum failure why) {
3364 const char *message;
3365
3366 if (listing) {
3367 close(fd);
3368 longjmp(listingbuf, 1);
3369 }
3370
3371 switch (why) {
3372 case unable_to_open:
3373 message = "Unable to open %s\n";
3374 break;
3375 case unable_to_read:
3376 message = "Unable to read %s\n";
3377 break;
3378 case unable_to_seek:
3379 message = "Unable to seek on %s\n";
3380 break;
3381 case unable_to_write:
3382 message = "Unable to write %s\n";
3383 break;
3384 case ioctl_error:
3385 message = "BLKGETSIZE ioctl failed on %s\n";
3386 break;
3387 default:
3388 message = "Fatal error\n";
3389 }
3390
3391 fputc('\n', stderr);
3392 fprintf(stderr, message, disk_device);
3393 exit(1);
3394}
3395
3396static void
Eric Andersend9261492004-06-28 23:50:31 +00003397seek_sector(off_t secno) {
Eric Andersen0a92f352004-03-30 09:21:54 +00003398 off_t offset = secno * sector_size;
3399 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003400 fdisk_fatal(unable_to_seek);
3401}
3402
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003403#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003404static void
Eric Andersend9261492004-06-28 23:50:31 +00003405write_sector(off_t secno, char *buf) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003406 seek_sector(secno);
3407 if (write(fd, buf, sector_size) != sector_size)
3408 fdisk_fatal(unable_to_write);
3409}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003410#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003411
3412/* Allocate a buffer and read a partition table sector */
3413static void
Eric Andersend9261492004-06-28 23:50:31 +00003414read_pte(struct pte *pe, off_t offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003415
3416 pe->offset = offset;
3417 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003418 seek_sector(offset);
3419 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3420 fdisk_fatal(unable_to_read);
3421#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003422 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003423#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003424 pe->part_table = pe->ext_pointer = NULL;
3425}
3426
3427static unsigned int
3428get_partition_start(const struct pte *pe) {
3429 return pe->offset + get_start_sect(pe->part_table);
3430}
3431
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003432#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003433/*
3434 * Avoid warning about DOS partitions when no DOS partition was changed.
3435 * Here a heuristic "is probably dos partition".
3436 * We might also do the opposite and warn in all cases except
3437 * for "is probably nondos partition".
3438 */
3439static int
3440is_dos_partition(int t) {
3441 return (t == 1 || t == 4 || t == 6 ||
3442 t == 0x0b || t == 0x0c || t == 0x0e ||
3443 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3444 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3445 t == 0xc1 || t == 0xc4 || t == 0xc6);
3446}
3447
3448static void
3449menu(void) {
3450#ifdef CONFIG_FEATURE_SUN_LABEL
3451 if (sun_label) {
3452 puts(_("Command action"));
3453 puts(_("\ta\ttoggle a read only flag")); /* sun */
3454 puts(_("\tb\tedit bsd disklabel"));
3455 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3456 puts(_("\td\tdelete a partition"));
3457 puts(_("\tl\tlist known partition types"));
3458 puts(_("\tm\tprint this menu"));
3459 puts(_("\tn\tadd a new partition"));
3460 puts(_("\to\tcreate a new empty DOS partition table"));
3461 puts(_("\tp\tprint the partition table"));
3462 puts(_("\tq\tquit without saving changes"));
3463 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3464 puts(_("\tt\tchange a partition's system id"));
3465 puts(_("\tu\tchange display/entry units"));
3466 puts(_("\tv\tverify the partition table"));
3467 puts(_("\tw\twrite table to disk and exit"));
3468#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3469 puts(_("\tx\textra functionality (experts only)"));
3470#endif
3471 } else
3472#endif
3473#ifdef CONFIG_FEATURE_SGI_LABEL
3474 if (sgi_label) {
3475 puts(_("Command action"));
3476 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3477 puts(_("\tb\tedit bootfile entry")); /* sgi */
3478 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3479 puts(_("\td\tdelete a partition"));
3480 puts(_("\tl\tlist known partition types"));
3481 puts(_("\tm\tprint this menu"));
3482 puts(_("\tn\tadd a new partition"));
3483 puts(_("\to\tcreate a new empty DOS partition table"));
3484 puts(_("\tp\tprint the partition table"));
3485 puts(_("\tq\tquit without saving changes"));
3486 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3487 puts(_("\tt\tchange a partition's system id"));
3488 puts(_("\tu\tchange display/entry units"));
3489 puts(_("\tv\tverify the partition table"));
3490 puts(_("\tw\twrite table to disk and exit"));
3491 } else
3492#endif
3493#ifdef CONFIG_FEATURE_AIX_LABEL
3494 if (aix_label) {
3495 puts(_("Command action"));
3496 puts(_("\tm\tprint this menu"));
3497 puts(_("\to\tcreate a new empty DOS partition table"));
3498 puts(_("\tq\tquit without saving changes"));
3499 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3500 } else
3501#endif
3502 {
3503 puts(_("Command action"));
3504 puts(_("\ta\ttoggle a bootable flag"));
3505 puts(_("\tb\tedit bsd disklabel"));
3506 puts(_("\tc\ttoggle the dos compatibility flag"));
3507 puts(_("\td\tdelete a partition"));
3508 puts(_("\tl\tlist known partition types"));
3509 puts(_("\tm\tprint this menu"));
3510 puts(_("\tn\tadd a new partition"));
3511 puts(_("\to\tcreate a new empty DOS partition table"));
3512 puts(_("\tp\tprint the partition table"));
3513 puts(_("\tq\tquit without saving changes"));
3514 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3515 puts(_("\tt\tchange a partition's system id"));
3516 puts(_("\tu\tchange display/entry units"));
3517 puts(_("\tv\tverify the partition table"));
3518 puts(_("\tw\twrite table to disk and exit"));
3519#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3520 puts(_("\tx\textra functionality (experts only)"));
3521#endif
3522 }
3523}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003524#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3525
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003526
3527#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3528static void
3529xmenu(void) {
3530#ifdef CONFIG_FEATURE_SUN_LABEL
3531 if (sun_label) {
3532 puts(_("Command action"));
3533 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3534 puts(_("\tc\tchange number of cylinders"));
3535 puts(_("\td\tprint the raw data in the partition table"));
3536 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3537 puts(_("\th\tchange number of heads"));
3538 puts(_("\ti\tchange interleave factor")); /*sun*/
3539 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3540 puts(_("\tm\tprint this menu"));
3541 puts(_("\tp\tprint the partition table"));
3542 puts(_("\tq\tquit without saving changes"));
3543 puts(_("\tr\treturn to main menu"));
3544 puts(_("\ts\tchange number of sectors/track"));
3545 puts(_("\tv\tverify the partition table"));
3546 puts(_("\tw\twrite table to disk and exit"));
3547 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
3548 } else
3549#endif
3550#ifdef CONFIG_FEATURE_SGI_LABEL
3551 if (sgi_label) {
3552 puts(_("Command action"));
3553 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3554 puts(_("\tc\tchange number of cylinders"));
3555 puts(_("\td\tprint the raw data in the partition table"));
3556 puts(_("\te\tlist extended partitions")); /* !sun */
3557 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3558 puts(_("\th\tchange number of heads"));
3559 puts(_("\tm\tprint this menu"));
3560 puts(_("\tp\tprint the partition table"));
3561 puts(_("\tq\tquit without saving changes"));
3562 puts(_("\tr\treturn to main menu"));
3563 puts(_("\ts\tchange number of sectors/track"));
3564 puts(_("\tv\tverify the partition table"));
3565 puts(_("\tw\twrite table to disk and exit"));
3566 } else
3567#endif
3568#ifdef CONFIG_FEATURE_AIX_LABEL
3569 if (aix_label) {
3570 puts(_("Command action"));
3571 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3572 puts(_("\tc\tchange number of cylinders"));
3573 puts(_("\td\tprint the raw data in the partition table"));
3574 puts(_("\te\tlist extended partitions")); /* !sun */
3575 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3576 puts(_("\th\tchange number of heads"));
3577 puts(_("\tm\tprint this menu"));
3578 puts(_("\tp\tprint the partition table"));
3579 puts(_("\tq\tquit without saving changes"));
3580 puts(_("\tr\treturn to main menu"));
3581 puts(_("\ts\tchange number of sectors/track"));
3582 puts(_("\tv\tverify the partition table"));
3583 puts(_("\tw\twrite table to disk and exit"));
3584 } else
3585#endif
3586 {
3587 puts(_("Command action"));
3588 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3589 puts(_("\tc\tchange number of cylinders"));
3590 puts(_("\td\tprint the raw data in the partition table"));
3591 puts(_("\te\tlist extended partitions")); /* !sun */
3592 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
3593#ifdef CONFIG_FEATURE_SGI_LABEL
3594 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3595#endif
3596 puts(_("\th\tchange number of heads"));
3597 puts(_("\tm\tprint this menu"));
3598 puts(_("\tp\tprint the partition table"));
3599 puts(_("\tq\tquit without saving changes"));
3600 puts(_("\tr\treturn to main menu"));
3601 puts(_("\ts\tchange number of sectors/track"));
3602 puts(_("\tv\tverify the partition table"));
3603 puts(_("\tw\twrite table to disk and exit"));
3604 }
3605}
3606#endif /* ADVANCED mode */
3607
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003608#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003609static const struct systypes *
3610get_sys_types(void) {
3611 return (
3612#ifdef CONFIG_FEATURE_SUN_LABEL
3613 sun_label ? sun_sys_types :
3614#endif
3615#ifdef CONFIG_FEATURE_SGI_LABEL
3616 sgi_label ? sgi_sys_types :
3617#endif
3618 i386_sys_types);
3619}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003620#else
3621#define get_sys_types() i386_sys_types
3622#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003623
3624static const char *partition_type(unsigned char type)
3625{
3626 int i;
3627 const struct systypes *types = get_sys_types();
3628
3629 for (i=0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003630 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003631 return types[i].name + 1;
3632
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003633 return _("Unknown");
3634}
3635
3636
3637#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3638static int
3639get_sysid(int i) {
3640 return (
3641#ifdef CONFIG_FEATURE_SUN_LABEL
3642 sun_label ? sunlabel->infos[i].id :
3643#endif
3644#ifdef CONFIG_FEATURE_SGI_LABEL
3645 sgi_label ? sgi_get_sysid(i) :
3646#endif
3647 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003648}
3649
3650void list_types(const struct systypes *sys)
3651{
3652 uint last[4], done = 0, next = 0, size;
3653 int i;
3654
3655 for (i = 0; sys[i].name; i++);
3656 size = i;
3657
3658 for (i = 3; i >= 0; i--)
3659 last[3 - i] = done += (size + i - done) / (i + 1);
3660 i = done = 0;
3661
3662 do {
3663 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003664 (unsigned char)sys[next].name[0],
3665 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003666 next = last[i++] + done;
3667 if (i > 3 || next >= last[i]) {
3668 i = 0;
3669 next = ++done;
3670 }
3671 } while (done < last[0]);
3672 putchar('\n');
3673}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003674#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003675
3676static int
3677is_cleared_partition(const struct partition *p) {
3678 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3679 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3680 get_start_sect(p) || get_nr_sects(p));
3681}
3682
3683static void
3684clear_partition(struct partition *p) {
3685 if (!p)
3686 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003687 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003688}
3689
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003690#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003691static void
Eric Andersend9261492004-06-28 23:50:31 +00003692set_partition(int i, int doext, off_t start, off_t stop, int sysid) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003693 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003694 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003695
3696 if (doext) {
3697 p = ptes[i].ext_pointer;
3698 offset = extended_offset;
3699 } else {
3700 p = ptes[i].part_table;
3701 offset = ptes[i].offset;
3702 }
3703 p->boot_ind = 0;
3704 p->sys_ind = sysid;
3705 set_start_sect(p, start - offset);
3706 set_nr_sects(p, stop - start + 1);
3707 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3708 start = heads*sectors*1024 - 1;
3709 set_hsc(p->head, p->sector, p->cyl, start);
3710 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3711 stop = heads*sectors*1024 - 1;
3712 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3713 ptes[i].changed = 1;
3714}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003715#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003716
3717static int
3718test_c(const char **m, const char *mesg) {
3719 int val = 0;
3720 if (!*m)
3721 fprintf(stderr, _("You must set"));
3722 else {
3723 fprintf(stderr, " %s", *m);
3724 val = 1;
3725 }
3726 *m = mesg;
3727 return val;
3728}
3729
3730static int
3731warn_geometry(void) {
3732 const char *m = NULL;
3733 int prev = 0;
3734
3735 if (!heads)
3736 prev = test_c(&m, _("heads"));
3737 if (!sectors)
3738 prev = test_c(&m, _("sectors"));
3739 if (!cylinders)
3740 prev = test_c(&m, _("cylinders"));
3741 if (!m)
3742 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003743
3744 fprintf(stderr, "%s%s.\n"
3745#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3746 "You can do this from the extra functions menu.\n"
3747#endif
3748 , prev ? _(" and ") : " ", m);
3749
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003750 return 1;
3751}
3752
3753static void update_units(void)
3754{
3755 int cyl_units = heads * sectors;
3756
3757 if (display_in_cyl_units && cyl_units)
3758 units_per_sector = cyl_units;
3759 else
3760 units_per_sector = 1; /* in sectors */
3761}
3762
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003763#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003764static void
3765warn_cylinders(void) {
3766 if (dos_label && cylinders > 1024 && !nowarn)
3767 fprintf(stderr, _("\n"
3768"The number of cylinders for this disk is set to %d.\n"
3769"There is nothing wrong with that, but this is larger than 1024,\n"
3770"and could in certain setups cause problems with:\n"
3771"1) software that runs at boot time (e.g., old versions of LILO)\n"
3772"2) booting and partitioning software from other OSs\n"
3773" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3774 cylinders);
3775}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003776#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003777
3778static void
3779read_extended(int ext) {
3780 int i;
3781 struct pte *pex;
3782 struct partition *p, *q;
3783
3784 ext_index = ext;
3785 pex = &ptes[ext];
3786 pex->ext_pointer = pex->part_table;
3787
3788 p = pex->part_table;
3789 if (!get_start_sect(p)) {
3790 fprintf(stderr,
3791 _("Bad offset in primary extended partition\n"));
3792 return;
3793 }
3794
3795 while (IS_EXTENDED (p->sys_ind)) {
3796 struct pte *pe = &ptes[partitions];
3797
3798 if (partitions >= MAXIMUM_PARTS) {
3799 /* This is not a Linux restriction, but
3800 this program uses arrays of size MAXIMUM_PARTS.
3801 Do not try to `improve' this test. */
3802 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003803#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003804 fprintf(stderr,
3805 _("Warning: deleting partitions after %d\n"),
3806 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003807 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003808#endif
3809 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003810 return;
3811 }
3812
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003813 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003814
3815 if (!extended_offset)
3816 extended_offset = get_start_sect(p);
3817
3818 q = p = pt_offset(pe->sectorbuffer, 0);
3819 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3820 if (IS_EXTENDED (p->sys_ind)) {
3821 if (pe->ext_pointer)
3822 fprintf(stderr,
3823 _("Warning: extra link "
3824 "pointer in partition table"
3825 " %d\n"), partitions + 1);
3826 else
3827 pe->ext_pointer = p;
3828 } else if (p->sys_ind) {
3829 if (pe->part_table)
3830 fprintf(stderr,
3831 _("Warning: ignoring extra "
3832 "data in partition table"
3833 " %d\n"), partitions + 1);
3834 else
3835 pe->part_table = p;
3836 }
3837 }
3838
3839 /* very strange code here... */
3840 if (!pe->part_table) {
3841 if (q != pe->ext_pointer)
3842 pe->part_table = q;
3843 else
3844 pe->part_table = q + 1;
3845 }
3846 if (!pe->ext_pointer) {
3847 if (q != pe->part_table)
3848 pe->ext_pointer = q;
3849 else
3850 pe->ext_pointer = q + 1;
3851 }
3852
3853 p = pe->ext_pointer;
3854 partitions++;
3855 }
3856
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003857#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003858 /* remove empty links */
3859 remove:
3860 for (i = 4; i < partitions; i++) {
3861 struct pte *pe = &ptes[i];
3862
3863 if (!get_nr_sects(pe->part_table) &&
3864 (partitions > 5 || ptes[4].part_table->sys_ind)) {
3865 printf("omitting empty partition (%d)\n", i+1);
3866 delete_partition(i);
3867 goto remove; /* numbering changed */
3868 }
3869 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003870#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003871}
3872
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003873#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003874static void
3875create_doslabel(void) {
3876 int i;
3877
3878 fprintf(stderr,
3879 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3880 "until you decide to write them. After that, of course, the previous\n"
3881 "content won't be recoverable.\n\n"));
3882#ifdef CONFIG_FEATURE_SUN_LABEL
3883 sun_nolabel(); /* otherwise always recognised as sun */
3884#endif
3885#ifdef CONFIG_FEATURE_SGI_LABEL
3886 sgi_nolabel(); /* otherwise always recognised as sgi */
3887#endif
3888#ifdef CONFIG_FEATURE_AIX_LABEL
3889 aix_label = 0;
3890#endif
3891#ifdef CONFIG_FEATURE_OSF_LABEL
3892 osf_label = 0;
3893 possibly_osf_label = 0;
3894#endif
3895 partitions = 4;
3896
3897 for (i = 510-64; i < 510; i++)
3898 MBRbuffer[i] = 0;
3899 write_part_table_flag(MBRbuffer);
3900 extended_offset = 0;
3901 set_all_unchanged();
3902 set_changed(0);
3903 get_boot(create_empty_dos);
3904}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003905#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003906
3907static void
3908get_sectorsize(void) {
3909 if (!user_set_sector_size &&
3910 get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
3911 int arg;
3912 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3913 sector_size = arg;
3914 if (sector_size != DEFAULT_SECTOR_SIZE)
3915 printf(_("Note: sector size is %d (not %d)\n"),
3916 sector_size, DEFAULT_SECTOR_SIZE);
3917 }
3918}
3919
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003920static inline void
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003921get_kernel_geometry(void) {
3922 struct hd_geometry geometry;
3923
3924 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3925 kern_heads = geometry.heads;
3926 kern_sectors = geometry.sectors;
3927 /* never use geometry.cylinders - it is truncated */
3928 }
3929}
3930
3931static void
3932get_partition_table_geometry(void) {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003933 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003934 struct partition *p;
3935 int i, h, s, hh, ss;
3936 int first = 1;
3937 int bad = 0;
3938
Eric Andersen3496fdc2006-01-30 23:09:20 +00003939 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003940 return;
3941
3942 hh = ss = 0;
3943 for (i=0; i<4; i++) {
3944 p = pt_offset(bufp, i);
3945 if (p->sys_ind != 0) {
3946 h = p->end_head + 1;
3947 s = (p->end_sector & 077);
3948 if (first) {
3949 hh = h;
3950 ss = s;
3951 first = 0;
3952 } else if (hh != h || ss != s)
3953 bad = 1;
3954 }
3955 }
3956
3957 if (!first && !bad) {
3958 pt_heads = hh;
3959 pt_sectors = ss;
3960 }
3961}
3962
3963void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003964get_geometry(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003965 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003966 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003967
3968 get_sectorsize();
3969 sec_fac = sector_size / 512;
3970#ifdef CONFIG_FEATURE_SUN_LABEL
3971 guess_device_type();
3972#endif
3973 heads = cylinders = sectors = 0;
3974 kern_heads = kern_sectors = 0;
3975 pt_heads = pt_sectors = 0;
3976
3977 get_kernel_geometry();
3978 get_partition_table_geometry();
3979
3980 heads = user_heads ? user_heads :
3981 pt_heads ? pt_heads :
3982 kern_heads ? kern_heads : 255;
3983 sectors = user_sectors ? user_sectors :
3984 pt_sectors ? pt_sectors :
3985 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003986 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3987 /* got bytes */
3988 } else {
3989 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003990
3991 if (ioctl(fd, BLKGETSIZE, &longsectors))
3992 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00003993 bytes = ((unsigned long long) longsectors) << 9;
3994 }
3995
3996 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003997
3998 sector_offset = 1;
3999 if (dos_compatible_flag)
4000 sector_offset = sectors;
4001
Eric Andersen040f4402003-07-30 08:40:37 +00004002 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004003 if (!cylinders)
4004 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004005}
4006
4007/*
4008 * Read MBR. Returns:
4009 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4010 * 0: found or created label
4011 * 1: I/O error
4012 */
4013int
4014get_boot(enum action what) {
4015 int i;
4016
4017 partitions = 4;
4018
4019 for (i = 0; i < 4; i++) {
4020 struct pte *pe = &ptes[i];
4021
4022 pe->part_table = pt_offset(MBRbuffer, i);
4023 pe->ext_pointer = NULL;
4024 pe->offset = 0;
4025 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004026#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004027 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004028#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004029 }
4030
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004031#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004032 if (what == create_empty_sun && check_sun_label())
4033 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004034#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004035
4036 memset(MBRbuffer, 0, 512);
4037
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004038#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004039 if (what == create_empty_dos)
4040 goto got_dos_table; /* skip reading disk */
4041
4042 if ((fd = open(disk_device, type_open)) < 0) {
4043 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4044 if (what == try_only)
4045 return 1;
4046 fdisk_fatal(unable_to_open);
4047 } else
4048 printf(_("You will not be able to write "
4049 "the partition table.\n"));
4050 }
4051
4052 if (512 != read(fd, MBRbuffer, 512)) {
4053 if (what == try_only)
4054 return 1;
4055 fdisk_fatal(unable_to_read);
4056 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004057#else
4058 if ((fd = open(disk_device, O_RDONLY)) < 0)
4059 return 1;
4060 if (512 != read(fd, MBRbuffer, 512))
4061 return 1;
4062#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004063
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004064 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004065
4066 update_units();
4067
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004068#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004069 if (check_sun_label())
4070 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004071#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004072
4073#ifdef CONFIG_FEATURE_SGI_LABEL
4074 if (check_sgi_label())
4075 return 0;
4076#endif
4077
4078#ifdef CONFIG_FEATURE_AIX_LABEL
4079 if (check_aix_label())
4080 return 0;
4081#endif
4082
4083#ifdef CONFIG_FEATURE_OSF_LABEL
4084 if (check_osf_label()) {
4085 possibly_osf_label = 1;
4086 if (!valid_part_table_flag(MBRbuffer)) {
4087 osf_label = 1;
4088 return 0;
4089 }
4090 printf(_("This disk has both DOS and BSD magic.\n"
4091 "Give the 'b' command to go to BSD mode.\n"));
4092 }
4093#endif
4094
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004095#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004096got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004097#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004098
4099 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004100#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4101 return -1;
4102#else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004103 switch(what) {
4104 case fdisk:
4105 fprintf(stderr,
4106 _("Device contains neither a valid DOS "
4107 "partition table, nor Sun, SGI or OSF "
4108 "disklabel\n"));
4109#ifdef __sparc__
4110#ifdef CONFIG_FEATURE_SUN_LABEL
4111 create_sunlabel();
4112#endif
4113#else
4114 create_doslabel();
4115#endif
4116 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004117 case try_only:
4118 return -1;
4119 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004120#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004121 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004122#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004123 break;
4124 default:
4125 fprintf(stderr, _("Internal error\n"));
4126 exit(1);
4127 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004128#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004129 }
4130
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004131#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004132 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004133#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004134 warn_geometry();
4135
4136 for (i = 0; i < 4; i++) {
4137 struct pte *pe = &ptes[i];
4138
4139 if (IS_EXTENDED (pe->part_table->sys_ind)) {
4140 if (partitions != 4)
4141 fprintf(stderr, _("Ignoring extra extended "
4142 "partition %d\n"), i + 1);
4143 else
4144 read_extended(i);
4145 }
4146 }
4147
4148 for (i = 3; i < partitions; i++) {
4149 struct pte *pe = &ptes[i];
4150
4151 if (!valid_part_table_flag(pe->sectorbuffer)) {
4152 fprintf(stderr,
4153 _("Warning: invalid flag 0x%04x of partition "
4154 "table %d will be corrected by w(rite)\n"),
4155 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004156#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004157 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004158#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004159 }
4160 }
4161
4162 return 0;
4163}
4164
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004165#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004166/*
4167 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4168 * If the user hits Enter, DFLT is returned.
4169 * Answers like +10 are interpreted as offsets from BASE.
4170 *
4171 * There is no default if DFLT is not between LOW and HIGH.
4172 */
4173static uint
4174read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4175{
4176 uint i;
4177 int default_ok = 1;
4178 static char *ms = NULL;
4179 static int mslen = 0;
4180
4181 if (!ms || strlen(mesg)+100 > mslen) {
4182 mslen = strlen(mesg)+200;
4183 ms = xrealloc(ms,mslen);
4184 }
4185
4186 if (dflt < low || dflt > high)
4187 default_ok = 0;
4188
4189 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004190 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004191 mesg, low, high, dflt);
4192 else
Eric Andersen040f4402003-07-30 08:40:37 +00004193 snprintf(ms, mslen, "%s (%u-%u): ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004194 mesg, low, high);
4195
4196 while (1) {
4197 int use_default = default_ok;
4198
4199 /* ask question and read answer */
4200 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4201 && *line_ptr != '-' && *line_ptr != '+')
4202 continue;
4203
Eric Andersen84bdea82004-05-19 10:49:17 +00004204 if (*line_ptr == '+' || *line_ptr == '-') {
Eric Andersenc48d49a2003-07-03 10:02:32 +00004205 int minus = (*line_ptr == '-');
4206 int absolute = 0;
4207
4208 i = atoi(line_ptr+1);
4209
4210 while (isdigit(*++line_ptr))
4211 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004212
Eric Andersenc48d49a2003-07-03 10:02:32 +00004213 switch (*line_ptr) {
4214 case 'c':
4215 case 'C':
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004216 if (!display_in_cyl_units)
4217 i *= heads * sectors;
4218 break;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004219 case 'K':
Eric Andersen040f4402003-07-30 08:40:37 +00004220 absolute = 1024;
4221 break;
4222 case 'k':
Eric Andersenc48d49a2003-07-03 10:02:32 +00004223 absolute = 1000;
4224 break;
4225 case 'm':
4226 case 'M':
4227 absolute = 1000000;
4228 break;
4229 case 'g':
4230 case 'G':
4231 absolute = 1000000000;
4232 break;
4233 default:
4234 break;
4235 }
4236 if (absolute) {
4237 unsigned long long bytes;
4238 unsigned long unit;
4239
4240 bytes = (unsigned long long) i * absolute;
4241 unit = sector_size * units_per_sector;
Eric Andersen84bdea82004-05-19 10:49:17 +00004242 bytes += unit/2; /* round */
Eric Andersenc48d49a2003-07-03 10:02:32 +00004243 bytes /= unit;
4244 i = bytes;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004245 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00004246 if (minus)
4247 i = -i;
4248 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004249 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004250 i = atoi(line_ptr);
4251 while (isdigit(*line_ptr)) {
4252 line_ptr++;
4253 use_default = 0;
4254 }
4255 }
4256 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004257 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004258 if (i >= low && i <= high)
4259 break;
4260 else
4261 printf(_("Value out of range.\n"));
4262 }
4263 return i;
4264}
4265
4266int
4267get_partition(int warn, int max) {
4268 struct pte *pe;
4269 int i;
4270
4271 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4272 pe = &ptes[i];
4273
4274 if (warn) {
4275 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4276#ifdef CONFIG_FEATURE_SUN_LABEL
4277 || (sun_label &&
4278 (!sunlabel->partitions[i].num_sectors ||
4279 !sunlabel->infos[i].id))
4280#endif
4281#ifdef CONFIG_FEATURE_SGI_LABEL
4282 || (sgi_label && (!sgi_get_num_sectors(i)))
4283#endif
4284 )
4285 fprintf(stderr,
4286 _("Warning: partition %d has empty type\n"),
4287 i+1);
4288 }
4289 return i;
4290}
4291
4292static int
4293get_existing_partition(int warn, int max) {
4294 int pno = -1;
4295 int i;
4296
4297 for (i = 0; i < max; i++) {
4298 struct pte *pe = &ptes[i];
4299 struct partition *p = pe->part_table;
4300
4301 if (p && !is_cleared_partition(p)) {
4302 if (pno >= 0)
4303 goto not_unique;
4304 pno = i;
4305 }
4306 }
4307 if (pno >= 0) {
4308 printf(_("Selected partition %d\n"), pno+1);
4309 return pno;
4310 }
4311 printf(_("No partition is defined yet!\n"));
4312 return -1;
4313
4314 not_unique:
4315 return get_partition(warn, max);
4316}
4317
4318static int
4319get_nonexisting_partition(int warn, int max) {
4320 int pno = -1;
4321 int i;
4322
4323 for (i = 0; i < max; i++) {
4324 struct pte *pe = &ptes[i];
4325 struct partition *p = pe->part_table;
4326
4327 if (p && is_cleared_partition(p)) {
4328 if (pno >= 0)
4329 goto not_unique;
4330 pno = i;
4331 }
4332 }
4333 if (pno >= 0) {
4334 printf(_("Selected partition %d\n"), pno+1);
4335 return pno;
4336 }
4337 printf(_("All primary partitions have been defined already!\n"));
4338 return -1;
4339
4340 not_unique:
4341 return get_partition(warn, max);
4342}
4343
4344
4345void change_units(void)
4346{
4347 display_in_cyl_units = !display_in_cyl_units;
4348 update_units();
4349 printf(_("Changing display/entry units to %s\n"),
4350 str_units(PLURAL));
4351}
4352
4353static void
4354toggle_active(int i) {
4355 struct pte *pe = &ptes[i];
4356 struct partition *p = pe->part_table;
4357
4358 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
4359 fprintf(stderr,
4360 _("WARNING: Partition %d is an extended partition\n"),
4361 i + 1);
4362 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4363 pe->changed = 1;
4364}
4365
4366static void
4367toggle_dos_compatibility_flag(void) {
4368 dos_compatible_flag = ~dos_compatible_flag;
4369 if (dos_compatible_flag) {
4370 sector_offset = sectors;
4371 printf(_("DOS Compatibility flag is set\n"));
4372 }
4373 else {
4374 sector_offset = 1;
4375 printf(_("DOS Compatibility flag is not set\n"));
4376 }
4377}
4378
4379static void
4380delete_partition(int i) {
4381 struct pte *pe = &ptes[i];
4382 struct partition *p = pe->part_table;
4383 struct partition *q = pe->ext_pointer;
4384
4385/* Note that for the fifth partition (i == 4) we don't actually
4386 * decrement partitions.
4387 */
4388
4389 if (warn_geometry())
4390 return; /* C/H/S not set */
4391 pe->changed = 1;
4392
4393#ifdef CONFIG_FEATURE_SUN_LABEL
4394 if (sun_label) {
4395 sun_delete_partition(i);
4396 return;
4397 }
4398#endif
4399#ifdef CONFIG_FEATURE_SGI_LABEL
4400 if (sgi_label) {
4401 sgi_delete_partition(i);
4402 return;
4403 }
4404#endif
4405
4406 if (i < 4) {
4407 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
4408 partitions = 4;
4409 ptes[ext_index].ext_pointer = NULL;
4410 extended_offset = 0;
4411 }
4412 clear_partition(p);
4413 return;
4414 }
4415
4416 if (!q->sys_ind && i > 4) {
4417 /* the last one in the chain - just delete */
4418 --partitions;
4419 --i;
4420 clear_partition(ptes[i].ext_pointer);
4421 ptes[i].changed = 1;
4422 } else {
4423 /* not the last one - further ones will be moved down */
4424 if (i > 4) {
4425 /* delete this link in the chain */
4426 p = ptes[i-1].ext_pointer;
4427 *p = *q;
4428 set_start_sect(p, get_start_sect(q));
4429 set_nr_sects(p, get_nr_sects(q));
4430 ptes[i-1].changed = 1;
4431 } else if (partitions > 5) { /* 5 will be moved to 4 */
4432 /* the first logical in a longer chain */
4433 pe = &ptes[5];
4434
4435 if (pe->part_table) /* prevent SEGFAULT */
4436 set_start_sect(pe->part_table,
4437 get_partition_start(pe) -
4438 extended_offset);
4439 pe->offset = extended_offset;
4440 pe->changed = 1;
4441 }
4442
4443 if (partitions > 5) {
4444 partitions--;
4445 while (i < partitions) {
4446 ptes[i] = ptes[i+1];
4447 i++;
4448 }
4449 } else
4450 /* the only logical: clear only */
4451 clear_partition(ptes[i].part_table);
4452 }
4453}
4454
4455static void
4456change_sysid(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004457 int i, sys, origsys;
4458 struct partition *p;
4459
Eric Andersen040f4402003-07-30 08:40:37 +00004460#ifdef CONFIG_FEATURE_SGI_LABEL
4461 /* If sgi_label then don't use get_existing_partition,
4462 let the user select a partition, since get_existing_partition()
4463 only works for Linux like partition tables. */
4464 if (!sgi_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004465 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004466 } else {
4467 i = get_partition(0, partitions);
4468 }
4469#else
4470 i = get_existing_partition(0, partitions);
4471#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004472 if (i == -1)
4473 return;
4474 p = ptes[i].part_table;
4475 origsys = sys = get_sysid(i);
4476
4477 /* if changing types T to 0 is allowed, then
4478 the reverse change must be allowed, too */
4479 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4480 printf(_("Partition %d does not exist yet!\n"), i + 1);
4481 else while (1) {
4482 sys = read_hex (get_sys_types());
4483
4484 if (!sys && !sgi_label && !sun_label) {
4485 printf(_("Type 0 means free space to many systems\n"
4486 "(but not to Linux). Having partitions of\n"
4487 "type 0 is probably unwise. You can delete\n"
4488 "a partition using the `d' command.\n"));
4489 /* break; */
4490 }
4491
4492 if (!sun_label && !sgi_label) {
4493 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
4494 printf(_("You cannot change a partition into"
4495 " an extended one or vice versa\n"
4496 "Delete it first.\n"));
4497 break;
4498 }
4499 }
4500
4501 if (sys < 256) {
4502#ifdef CONFIG_FEATURE_SUN_LABEL
4503 if (sun_label && i == 2 && sys != WHOLE_DISK)
4504 printf(_("Consider leaving partition 3 "
4505 "as Whole disk (5),\n"
4506 "as SunOS/Solaris expects it and "
4507 "even Linux likes it.\n\n"));
4508#endif
4509#ifdef CONFIG_FEATURE_SGI_LABEL
4510 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4511 || (i == 8 && sys != 0)))
4512 printf(_("Consider leaving partition 9 "
4513 "as volume header (0),\nand "
4514 "partition 11 as entire volume (6)"
4515 "as IRIX expects it.\n\n"));
4516#endif
4517 if (sys == origsys)
4518 break;
4519#ifdef CONFIG_FEATURE_SUN_LABEL
4520 if (sun_label) {
4521 sun_change_sysid(i, sys);
4522 } else
4523#endif
4524#ifdef CONFIG_FEATURE_SGI_LABEL
4525 if (sgi_label) {
4526 sgi_change_sysid(i, sys);
4527 } else
4528#endif
4529 p->sys_ind = sys;
4530 printf (_("Changed system type of partition %d "
4531 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004532 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004533 ptes[i].changed = 1;
4534 if (is_dos_partition(origsys) ||
4535 is_dos_partition(sys))
4536 dos_changed = 1;
4537 break;
4538 }
4539 }
4540}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004541#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4542
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004543
4544/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4545 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4546 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4547 * Lubkin Oct. 1991). */
4548
4549static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
4550 int spc = heads * sectors;
4551
4552 *c = ls / spc;
4553 ls = ls % spc;
4554 *h = ls / sectors;
4555 *s = ls % sectors + 1; /* sectors count from 1 */
4556}
4557
4558static void check_consistency(const struct partition *p, int partition) {
4559 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4560 uint pec, peh, pes; /* physical ending c, h, s */
4561 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4562 uint lec, leh, les; /* logical ending c, h, s */
4563
4564 if (!heads || !sectors || (partition >= 4))
4565 return; /* do not check extended partitions */
4566
4567/* physical beginning c, h, s */
4568 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4569 pbh = p->head;
4570 pbs = p->sector & 0x3f;
4571
4572/* physical ending c, h, s */
4573 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4574 peh = p->end_head;
4575 pes = p->end_sector & 0x3f;
4576
4577/* compute logical beginning (c, h, s) */
4578 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4579
4580/* compute logical ending (c, h, s) */
4581 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4582
4583/* Same physical / logical beginning? */
4584 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4585 printf(_("Partition %d has different physical/logical "
4586 "beginnings (non-Linux?):\n"), partition + 1);
4587 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4588 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4589 }
4590
4591/* Same physical / logical ending? */
4592 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4593 printf(_("Partition %d has different physical/logical "
4594 "endings:\n"), partition + 1);
4595 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4596 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4597 }
4598
4599#if 0
4600/* Beginning on cylinder boundary? */
4601 if (pbh != !pbc || pbs != 1) {
4602 printf(_("Partition %i does not start on cylinder "
4603 "boundary:\n"), partition + 1);
4604 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4605 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4606 }
4607#endif
4608
4609/* Ending on cylinder boundary? */
4610 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004611 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004612 partition + 1);
4613#if 0
4614 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4615 printf(_("should be (%d, %d, %d)\n"),
4616 pec, heads - 1, sectors);
4617#endif
4618 }
4619}
4620
4621static void
4622list_disk_geometry(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00004623 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004624 long megabytes = bytes/1000000;
4625
4626 if (megabytes < 10000)
4627 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4628 disk_device, megabytes, bytes);
4629 else
4630 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4631 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4632 printf(_("%d heads, %d sectors/track, %d cylinders"),
4633 heads, sectors, cylinders);
4634 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004635 printf(_(", total %llu sectors"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004636 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004637 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004638 str_units(PLURAL),
4639 units_per_sector, sector_size, units_per_sector * sector_size);
4640}
4641
4642/*
4643 * Check whether partition entries are ordered by their starting positions.
4644 * Return 0 if OK. Return i if partition i should have been earlier.
4645 * Two separate checks: primary and logical partitions.
4646 */
4647static int
4648wrong_p_order(int *prev) {
4649 const struct pte *pe;
4650 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004651 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004652 int i, last_i = 0;
4653
4654 for (i = 0 ; i < partitions; i++) {
4655 if (i == 4) {
4656 last_i = 4;
4657 last_p_start_pos = 0;
4658 }
4659 pe = &ptes[i];
4660 if ((p = pe->part_table)->sys_ind) {
4661 p_start_pos = get_partition_start(pe);
4662
4663 if (last_p_start_pos > p_start_pos) {
4664 if (prev)
4665 *prev = last_i;
4666 return i;
4667 }
4668
4669 last_p_start_pos = p_start_pos;
4670 last_i = i;
4671 }
4672 }
4673 return 0;
4674}
4675
4676#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4677/*
4678 * Fix the chain of logicals.
4679 * extended_offset is unchanged, the set of sectors used is unchanged
4680 * The chain is sorted so that sectors increase, and so that
4681 * starting sectors increase.
4682 *
4683 * After this it may still be that cfdisk doesnt like the table.
4684 * (This is because cfdisk considers expanded parts, from link to
4685 * end of partition, and these may still overlap.)
4686 * Now
4687 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4688 * may help.
4689 */
4690static void
4691fix_chain_of_logicals(void) {
4692 int j, oj, ojj, sj, sjj;
4693 struct partition *pj,*pjj,tmp;
4694
4695 /* Stage 1: sort sectors but leave sector of part 4 */
4696 /* (Its sector is the global extended_offset.) */
4697 stage1:
4698 for (j = 5; j < partitions-1; j++) {
4699 oj = ptes[j].offset;
4700 ojj = ptes[j+1].offset;
4701 if (oj > ojj) {
4702 ptes[j].offset = ojj;
4703 ptes[j+1].offset = oj;
4704 pj = ptes[j].part_table;
4705 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4706 pjj = ptes[j+1].part_table;
4707 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4708 set_start_sect(ptes[j-1].ext_pointer,
4709 ojj-extended_offset);
4710 set_start_sect(ptes[j].ext_pointer,
4711 oj-extended_offset);
4712 goto stage1;
4713 }
4714 }
4715
4716 /* Stage 2: sort starting sectors */
4717 stage2:
4718 for (j = 4; j < partitions-1; j++) {
4719 pj = ptes[j].part_table;
4720 pjj = ptes[j+1].part_table;
4721 sj = get_start_sect(pj);
4722 sjj = get_start_sect(pjj);
4723 oj = ptes[j].offset;
4724 ojj = ptes[j+1].offset;
4725 if (oj+sj > ojj+sjj) {
4726 tmp = *pj;
4727 *pj = *pjj;
4728 *pjj = tmp;
4729 set_start_sect(pj, ojj+sjj-oj);
4730 set_start_sect(pjj, oj+sj-ojj);
4731 goto stage2;
4732 }
4733 }
4734
4735 /* Probably something was changed */
4736 for (j = 4; j < partitions; j++)
4737 ptes[j].changed = 1;
4738}
4739
4740
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004741static void
4742fix_partition_table_order(void) {
4743 struct pte *pei, *pek;
4744 int i,k;
4745
4746 if (!wrong_p_order(NULL)) {
4747 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4748 return;
4749 }
4750
4751 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4752 /* partition i should have come earlier, move it */
4753 /* We have to move data in the MBR */
4754 struct partition *pi, *pk, *pe, pbuf;
4755 pei = &ptes[i];
4756 pek = &ptes[k];
4757
4758 pe = pei->ext_pointer;
4759 pei->ext_pointer = pek->ext_pointer;
4760 pek->ext_pointer = pe;
4761
4762 pi = pei->part_table;
4763 pk = pek->part_table;
4764
4765 memmove(&pbuf, pi, sizeof(struct partition));
4766 memmove(pi, pk, sizeof(struct partition));
4767 memmove(pk, &pbuf, sizeof(struct partition));
4768
4769 pei->changed = pek->changed = 1;
4770 }
4771
4772 if (i)
4773 fix_chain_of_logicals();
4774
4775 printf("Done.\n");
4776
4777}
4778#endif
4779
4780static void
4781list_table(int xtra) {
4782 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004783 int i, w;
4784
4785#ifdef CONFIG_FEATURE_SUN_LABEL
4786 if (sun_label) {
4787 sun_list_table(xtra);
4788 return;
4789 }
4790#endif
4791
4792#ifdef CONFIG_FEATURE_SGI_LABEL
4793 if (sgi_label) {
4794 sgi_list_table(xtra);
4795 return;
4796 }
4797#endif
4798
4799 list_disk_geometry();
4800
4801#ifdef CONFIG_FEATURE_OSF_LABEL
4802 if (osf_label) {
4803 xbsd_print_disklabel(xtra);
4804 return;
4805 }
4806#endif
4807
4808 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4809 but if the device name ends in a digit, say /dev/foo1,
4810 then the partition is called /dev/foo1p3. */
4811 w = strlen(disk_device);
4812 if (w && isdigit(disk_device[w-1]))
4813 w++;
4814 if (w < 5)
4815 w = 5;
4816
4817 printf(_("%*s Boot Start End Blocks Id System\n"),
4818 w+1, _("Device"));
4819
4820 for (i = 0; i < partitions; i++) {
4821 const struct pte *pe = &ptes[i];
4822
4823 p = pe->part_table;
4824 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004825 off_t psects = get_nr_sects(p);
4826 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004827 unsigned int podd = 0;
4828
4829 if (sector_size < 1024) {
4830 pblocks /= (1024 / sector_size);
4831 podd = psects % (1024 / sector_size);
4832 }
4833 if (sector_size > 1024)
4834 pblocks *= (sector_size / 1024);
4835 printf(
Eric Andersend9261492004-06-28 23:50:31 +00004836 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004837 partname(disk_device, i+1, w+2),
4838/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4839 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004840/* start */ (unsigned long long) cround(get_partition_start(pe)),
4841/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004842 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004843/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004844/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004845/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004846 check_consistency(p, i);
4847 }
4848 }
4849
4850 /* Is partition table in disk order? It need not be, but... */
4851 /* partition table entries are not checked for correct order if this
4852 is a sgi, sun or aix labeled disk... */
4853 if (dos_label && wrong_p_order(NULL)) {
4854 printf(_("\nPartition table entries are not in disk order\n"));
4855 }
4856}
4857
4858#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4859static void
4860x_list_table(int extend) {
4861 const struct pte *pe;
4862 const struct partition *p;
4863 int i;
4864
4865 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4866 disk_device, heads, sectors, cylinders);
4867 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4868 for (i = 0 ; i < partitions; i++) {
4869 pe = &ptes[i];
4870 p = (extend ? pe->ext_pointer : pe->part_table);
4871 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004872 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004873 i + 1, p->boot_ind, p->head,
4874 sector(p->sector),
4875 cylinder(p->sector, p->cyl), p->end_head,
4876 sector(p->end_sector),
4877 cylinder(p->end_sector, p->end_cyl),
4878 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4879 if (p->sys_ind)
4880 check_consistency(p, i);
4881 }
4882 }
4883}
4884#endif
4885
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004886#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004887static void
Eric Andersend9261492004-06-28 23:50:31 +00004888fill_bounds(off_t *first, off_t *last) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004889 int i;
4890 const struct pte *pe = &ptes[0];
4891 const struct partition *p;
4892
4893 for (i = 0; i < partitions; pe++,i++) {
4894 p = pe->part_table;
4895 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
4896 first[i] = 0xffffffff;
4897 last[i] = 0;
4898 } else {
4899 first[i] = get_partition_start(pe);
4900 last[i] = first[i] + get_nr_sects(p) - 1;
4901 }
4902 }
4903}
4904
4905static void
Eric Andersend9261492004-06-28 23:50:31 +00004906check(int n, uint h, uint s, uint c, off_t start) {
4907 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004908
4909 real_s = sector(s) - 1;
4910 real_c = cylinder(s, c);
4911 total = (real_c * sectors + real_s) * heads + h;
4912 if (!total)
4913 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4914 if (h >= heads)
4915 fprintf(stderr,
4916 _("Partition %d: head %d greater than maximum %d\n"),
4917 n, h + 1, heads);
4918 if (real_s >= sectors)
4919 fprintf(stderr, _("Partition %d: sector %d greater than "
4920 "maximum %d\n"), n, s, sectors);
4921 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004922 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4923 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004924 if (cylinders <= 1024 && start != total)
4925 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004926 _("Partition %d: previous sectors %llu disagrees with "
4927 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004928}
4929
4930static void
4931verify(void) {
4932 int i, j;
4933 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00004934 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004935 struct partition *p;
4936
4937 if (warn_geometry())
4938 return;
4939
4940#ifdef CONFIG_FEATURE_SUN_LABEL
4941 if (sun_label) {
4942 verify_sun();
4943 return;
4944 }
4945#endif
4946#ifdef CONFIG_FEATURE_SGI_LABEL
4947 if (sgi_label) {
4948 verify_sgi(1);
4949 return;
4950 }
4951#endif
4952
4953 fill_bounds(first, last);
4954 for (i = 0; i < partitions; i++) {
4955 struct pte *pe = &ptes[i];
4956
4957 p = pe->part_table;
4958 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
4959 check_consistency(p, i);
4960 if (get_partition_start(pe) < first[i])
4961 printf(_("Warning: bad start-of-data in "
4962 "partition %d\n"), i + 1);
4963 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4964 last[i]);
4965 total += last[i] + 1 - first[i];
4966 for (j = 0; j < i; j++)
4967 if ((first[i] >= first[j] && first[i] <= last[j])
4968 || ((last[i] <= last[j] && last[i] >= first[j]))) {
4969 printf(_("Warning: partition %d overlaps "
4970 "partition %d.\n"), j + 1, i + 1);
4971 total += first[i] >= first[j] ?
4972 first[i] : first[j];
4973 total -= last[i] <= last[j] ?
4974 last[i] : last[j];
4975 }
4976 }
4977 }
4978
4979 if (extended_offset) {
4980 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00004981 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004982 get_nr_sects(pex->part_table) - 1;
4983
4984 for (i = 4; i < partitions; i++) {
4985 total++;
4986 p = ptes[i].part_table;
4987 if (!p->sys_ind) {
4988 if (i != 4 || i + 1 < partitions)
4989 printf(_("Warning: partition %d "
4990 "is empty\n"), i + 1);
4991 }
4992 else if (first[i] < extended_offset ||
4993 last[i] > e_last)
4994 printf(_("Logical partition %d not entirely in "
4995 "partition %d\n"), i + 1, ext_index + 1);
4996 }
4997 }
4998
4999 if (total > heads * sectors * cylinders)
5000 printf(_("Total allocated sectors %d greater than the maximum "
5001 "%d\n"), total, heads * sectors * cylinders);
5002 else if ((total = heads * sectors * cylinders - total) != 0)
5003 printf(_("%d unallocated sectors\n"), total);
5004}
5005
5006static void
5007add_partition(int n, int sys) {
5008 char mesg[256]; /* 48 does not suffice in Japanese */
5009 int i, readed = 0;
5010 struct partition *p = ptes[n].part_table;
5011 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005012 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005013 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005014 first[partitions], last[partitions];
5015
5016 if (p && p->sys_ind) {
5017 printf(_("Partition %d is already defined. Delete "
5018 "it before re-adding it.\n"), n + 1);
5019 return;
5020 }
5021 fill_bounds(first, last);
5022 if (n < 4) {
5023 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005024 if (display_in_cyl_units || !total_number_of_sectors)
5025 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005026 else
Eric Andersen040f4402003-07-30 08:40:37 +00005027 llimit = total_number_of_sectors - 1;
5028 limit = llimit;
5029 if (limit != llimit)
5030 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005031 if (extended_offset) {
5032 first[ext_index] = extended_offset;
5033 last[ext_index] = get_start_sect(q) +
5034 get_nr_sects(q) - 1;
5035 }
5036 } else {
5037 start = extended_offset + sector_offset;
5038 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5039 }
5040 if (display_in_cyl_units)
5041 for (i = 0; i < partitions; i++)
5042 first[i] = (cround(first[i]) - 1) * units_per_sector;
5043
5044 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5045 do {
5046 temp = start;
5047 for (i = 0; i < partitions; i++) {
5048 int lastplusoff;
5049
5050 if (start == ptes[i].offset)
5051 start += sector_offset;
5052 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
5053 if (start >= first[i] && start <= lastplusoff)
5054 start = lastplusoff + 1;
5055 }
5056 if (start > limit)
5057 break;
5058 if (start >= temp+units_per_sector && readed) {
Eric Andersend9261492004-06-28 23:50:31 +00005059 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005060 temp = start;
5061 readed = 0;
5062 }
5063 if (!readed && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005064 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005065
5066 saved_start = start;
5067 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5068 0, mesg);
5069 if (display_in_cyl_units) {
5070 start = (start - 1) * units_per_sector;
5071 if (start < saved_start) start = saved_start;
5072 }
5073 readed = 1;
5074 }
5075 } while (start != temp || !readed);
5076 if (n > 4) { /* NOT for fifth partition */
5077 struct pte *pe = &ptes[n];
5078
5079 pe->offset = start - sector_offset;
5080 if (pe->offset == extended_offset) { /* must be corrected */
5081 pe->offset++;
5082 if (sector_offset == 1)
5083 start++;
5084 }
5085 }
5086
5087 for (i = 0; i < partitions; i++) {
5088 struct pte *pe = &ptes[i];
5089
5090 if (start < pe->offset && limit >= pe->offset)
5091 limit = pe->offset - 1;
5092 if (start < first[i] && limit >= first[i])
5093 limit = first[i] - 1;
5094 }
5095 if (start > limit) {
5096 printf(_("No free sectors available\n"));
5097 if (n > 4)
5098 partitions--;
5099 return;
5100 }
5101 if (cround(start) == cround(limit)) {
5102 stop = limit;
5103 } else {
5104 snprintf(mesg, sizeof(mesg),
5105 _("Last %s or +size or +sizeM or +sizeK"),
5106 str_units(SINGULAR));
5107 stop = read_int(cround(start), cround(limit), cround(limit),
5108 cround(start), mesg);
5109 if (display_in_cyl_units) {
5110 stop = stop * units_per_sector - 1;
5111 if (stop >limit)
5112 stop = limit;
5113 }
5114 }
5115
5116 set_partition(n, 0, start, stop, sys);
5117 if (n > 4)
5118 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5119
5120 if (IS_EXTENDED (sys)) {
5121 struct pte *pe4 = &ptes[4];
5122 struct pte *pen = &ptes[n];
5123
5124 ext_index = n;
5125 pen->ext_pointer = p;
5126 pe4->offset = extended_offset = start;
5127 pe4->sectorbuffer = xcalloc(1, sector_size);
5128 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5129 pe4->ext_pointer = pe4->part_table + 1;
5130 pe4->changed = 1;
5131 partitions = 5;
5132 }
5133}
5134
5135static void
5136add_logical(void) {
5137 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5138 struct pte *pe = &ptes[partitions];
5139
5140 pe->sectorbuffer = xcalloc(1, sector_size);
5141 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5142 pe->ext_pointer = pe->part_table + 1;
5143 pe->offset = 0;
5144 pe->changed = 1;
5145 partitions++;
5146 }
5147 add_partition(partitions - 1, LINUX_NATIVE);
5148}
5149
5150static void
5151new_partition(void) {
5152 int i, free_primary = 0;
5153
5154 if (warn_geometry())
5155 return;
5156
5157#ifdef CONFIG_FEATURE_SUN_LABEL
5158 if (sun_label) {
5159 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5160 return;
5161 }
5162#endif
5163#ifdef CONFIG_FEATURE_SGI_LABEL
5164 if (sgi_label) {
5165 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5166 return;
5167 }
5168#endif
5169#ifdef CONFIG_FEATURE_AIX_LABEL
5170 if (aix_label) {
5171 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5172 "\n\tIf you want to add DOS-type partitions, create"
5173 "\n\ta new empty DOS partition table first. (Use o.)"
5174 "\n\tWARNING: "
5175 "This will destroy the present disk contents.\n"));
5176 return;
5177 }
5178#endif
5179
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005180 for (i = 0; i < 4; i++)
5181 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005182
5183 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005184 printf(_("The maximum number of partitions has been created\n"));
5185 return;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005186 }
5187
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005188 if (!free_primary) {
5189 if (extended_offset)
5190 add_logical();
5191 else
5192 printf(_("You must delete some partition and add "
5193 "an extended partition first\n"));
5194 } else {
5195 char c, line[LINE_LENGTH];
5196 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5197 "partition (1-4)\n",
5198 "Command action", (extended_offset ?
5199 "l logical (5 or over)" : "e extended"));
5200 while (1) {
5201 if ((c = read_char(line)) == 'p' || c == 'P') {
5202 i = get_nonexisting_partition(0, 4);
5203 if (i >= 0)
5204 add_partition(i, LINUX_NATIVE);
5205 return;
5206 }
5207 else if (c == 'l' && extended_offset) {
5208 add_logical();
5209 return;
5210 }
5211 else if (c == 'e' && !extended_offset) {
5212 i = get_nonexisting_partition(0, 4);
5213 if (i >= 0)
5214 add_partition(i, EXTENDED);
5215 return;
5216 }
5217 else
5218 printf(_("Invalid partition number "
5219 "for type `%c'\n"), c);
5220 }
5221 }
5222}
5223
5224static void
5225write_table(void) {
5226 int i;
5227
5228 if (dos_label) {
5229 for (i=0; i<3; i++)
5230 if (ptes[i].changed)
5231 ptes[3].changed = 1;
5232 for (i = 3; i < partitions; i++) {
5233 struct pte *pe = &ptes[i];
5234
5235 if (pe->changed) {
5236 write_part_table_flag(pe->sectorbuffer);
5237 write_sector(pe->offset, pe->sectorbuffer);
5238 }
5239 }
5240 }
5241#ifdef CONFIG_FEATURE_SGI_LABEL
5242 else if (sgi_label) {
5243 /* no test on change? the printf below might be mistaken */
5244 sgi_write_table();
5245 }
5246#endif
5247#ifdef CONFIG_FEATURE_SUN_LABEL
5248 else if (sun_label) {
5249 int needw = 0;
5250
5251 for (i=0; i<8; i++)
5252 if (ptes[i].changed)
5253 needw = 1;
5254 if (needw)
5255 sun_write_table();
5256 }
5257#endif
5258
5259 printf(_("The partition table has been altered!\n\n"));
5260 reread_partition_table(1);
5261}
5262
5263void
5264reread_partition_table(int leave) {
5265 int error = 0;
5266 int i;
5267
5268 printf(_("Calling ioctl() to re-read partition table.\n"));
5269 sync();
5270 sleep(2);
5271 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5272 error = errno;
5273 } else {
5274 /* some kernel versions (1.2.x) seem to have trouble
5275 rereading the partition table, but if asked to do it
5276 twice, the second time works. - biro@yggdrasil.com */
5277 sync();
5278 sleep(2);
5279 if ((i = ioctl(fd, BLKRRPART)) != 0)
5280 error = errno;
5281 }
5282
5283 if (i) {
5284 printf(_("\nWARNING: Re-reading the partition table "
5285 "failed with error %d: %s.\n"
5286 "The kernel still uses the old table.\n"
5287 "The new table will be used "
5288 "at the next reboot.\n"),
5289 error, strerror(error));
5290 }
5291
5292 if (dos_changed)
5293 printf(
5294 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5295 "partitions, please see the fdisk manual page for additional\n"
5296 "information.\n"));
5297
5298 if (leave) {
5299 close(fd);
5300
5301 printf(_("Syncing disks.\n"));
5302 sync();
5303 sleep(4); /* for sync() */
5304 exit(!!i);
5305 }
5306}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005307#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005308
5309#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5310#define MAX_PER_LINE 16
5311static void
5312print_buffer(char pbuffer[]) {
5313 int i,
5314 l;
5315
5316 for (i = 0, l = 0; i < sector_size; i++, l++) {
5317 if (l == 0)
5318 printf("0x%03X:", i);
5319 printf(" %02X", (unsigned char) pbuffer[i]);
5320 if (l == MAX_PER_LINE - 1) {
5321 printf("\n");
5322 l = -1;
5323 }
5324 }
5325 if (l > 0)
5326 printf("\n");
5327 printf("\n");
5328}
5329
5330
5331static void
5332print_raw(void) {
5333 int i;
5334
5335 printf(_("Device: %s\n"), disk_device);
5336#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5337 if (sun_label || sgi_label)
5338 print_buffer(MBRbuffer);
5339 else
5340#endif
5341 for (i = 3; i < partitions; i++)
5342 print_buffer(ptes[i].sectorbuffer);
5343}
5344
5345static void
5346move_begin(int i) {
5347 struct pte *pe = &ptes[i];
5348 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005349 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005350
5351 if (warn_geometry())
5352 return;
5353 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
5354 printf(_("Partition %d has no data area\n"), i + 1);
5355 return;
5356 }
5357 first = get_partition_start(pe);
5358 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5359 _("New beginning of data")) - pe->offset;
5360
5361 if (new != get_nr_sects(p)) {
5362 first = get_nr_sects(p) + get_start_sect(p) - new;
5363 set_nr_sects(p, first);
5364 set_start_sect(p, new);
5365 pe->changed = 1;
5366 }
5367}
5368
5369static void
5370xselect(void) {
5371 char c;
5372
5373 while(1) {
5374 putchar('\n');
5375 c = tolower(read_char(_("Expert command (m for help): ")));
5376 switch (c) {
5377 case 'a':
5378#ifdef CONFIG_FEATURE_SUN_LABEL
5379 if (sun_label)
5380 sun_set_alt_cyl();
5381#endif
5382 break;
5383 case 'b':
5384 if (dos_label)
5385 move_begin(get_partition(0, partitions));
5386 break;
5387 case 'c':
5388 user_cylinders = cylinders =
5389 read_int(1, cylinders, 1048576, 0,
5390 _("Number of cylinders"));
5391#ifdef CONFIG_FEATURE_SUN_LABEL
5392 if (sun_label)
5393 sun_set_ncyl(cylinders);
5394#endif
5395 if (dos_label)
5396 warn_cylinders();
5397 break;
5398 case 'd':
5399 print_raw();
5400 break;
5401 case 'e':
5402#ifdef CONFIG_FEATURE_SGI_LABEL
5403 if (sgi_label)
5404 sgi_set_xcyl();
5405 else
5406#endif
5407#ifdef CONFIG_FEATURE_SUN_LABEL
5408 if (sun_label)
5409 sun_set_xcyl();
5410 else
5411#endif
5412 if (dos_label)
5413 x_list_table(1);
5414 break;
5415 case 'f':
5416 if (dos_label)
5417 fix_partition_table_order();
5418 break;
5419 case 'g':
5420#ifdef CONFIG_FEATURE_SGI_LABEL
5421 create_sgilabel();
5422#endif
5423 break;
5424 case 'h':
5425 user_heads = heads = read_int(1, heads, 256, 0,
5426 _("Number of heads"));
5427 update_units();
5428 break;
5429 case 'i':
5430#ifdef CONFIG_FEATURE_SUN_LABEL
5431 if (sun_label)
5432 sun_set_ilfact();
5433#endif
5434 break;
5435 case 'o':
5436#ifdef CONFIG_FEATURE_SUN_LABEL
5437 if (sun_label)
5438 sun_set_rspeed();
5439#endif
5440 break;
5441 case 'p':
5442#ifdef CONFIG_FEATURE_SUN_LABEL
5443 if (sun_label)
5444 list_table(1);
5445 else
5446#endif
5447 x_list_table(0);
5448 break;
5449 case 'q':
5450 close(fd);
5451 printf("\n");
5452 exit(0);
5453 case 'r':
5454 return;
5455 case 's':
5456 user_sectors = sectors = read_int(1, sectors, 63, 0,
5457 _("Number of sectors"));
5458 if (dos_compatible_flag) {
5459 sector_offset = sectors;
5460 fprintf(stderr, _("Warning: setting "
5461 "sector offset for DOS "
5462 "compatiblity\n"));
5463 }
5464 update_units();
5465 break;
5466 case 'v':
5467 verify();
5468 break;
5469 case 'w':
5470 write_table(); /* does not return */
5471 break;
5472 case 'y':
5473#ifdef CONFIG_FEATURE_SUN_LABEL
5474 if (sun_label)
5475 sun_set_pcylcount();
5476#endif
5477 break;
5478 default:
5479 xmenu();
5480 }
5481 }
5482}
5483#endif /* ADVANCED mode */
5484
5485static int
5486is_ide_cdrom_or_tape(const char *device) {
5487 FILE *procf;
5488 char buf[100];
5489 struct stat statbuf;
5490 int is_ide = 0;
5491
5492 /* No device was given explicitly, and we are trying some
5493 likely things. But opening /dev/hdc may produce errors like
5494 "hdc: tray open or drive not ready"
5495 if it happens to be a CD-ROM drive. It even happens that
5496 the process hangs on the attempt to read a music CD.
5497 So try to be careful. This only works since 2.1.73. */
5498
5499 if (strncmp("/dev/hd", device, 7))
5500 return 0;
5501
5502 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5503 procf = fopen(buf, "r");
5504 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5505 is_ide = (!strncmp(buf, "cdrom", 5) ||
5506 !strncmp(buf, "tape", 4));
5507 else
5508 /* Now when this proc file does not exist, skip the
5509 device when it is read-only. */
5510 if (stat(device, &statbuf) == 0)
5511 is_ide = ((statbuf.st_mode & 0222) == 0);
5512
5513 if (procf)
5514 fclose(procf);
5515 return is_ide;
5516}
5517
5518static void
5519try(const char *device, int user_specified) {
5520 int gb;
5521
5522 disk_device = device;
5523 if (setjmp(listingbuf))
5524 return;
5525 if (!user_specified)
5526 if (is_ide_cdrom_or_tape(device))
5527 return;
5528 if ((fd = open(disk_device, type_open)) >= 0) {
5529 gb = get_boot(try_only);
5530 if (gb > 0) { /* I/O error */
5531 close(fd);
5532 } else if (gb < 0) { /* no DOS signature */
5533 list_disk_geometry();
5534 if (aix_label)
5535 return;
5536#ifdef CONFIG_FEATURE_OSF_LABEL
5537 if (btrydev(device) < 0)
5538#endif
5539 fprintf(stderr,
5540 _("Disk %s doesn't contain a valid "
5541 "partition table\n"), device);
5542 close(fd);
5543 } else {
5544 close(fd);
5545 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005546#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005547 if (!sun_label && partitions > 4)
5548 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005549#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005550 }
5551 } else {
5552 /* Ignore other errors, since we try IDE
5553 and SCSI hard disks which may not be
5554 installed on the system. */
5555 if (errno == EACCES) {
5556 fprintf(stderr, _("Cannot open %s\n"), device);
5557 return;
5558 }
5559 }
5560}
5561
5562/* for fdisk -l: try all things in /proc/partitions
5563 that look like a partition name (do not end in a digit) */
5564static void
5565tryprocpt(void) {
5566 FILE *procpt;
5567 char line[100], ptname[100], devname[120], *s;
5568 int ma, mi, sz;
5569
Manuel Novoa III cad53642003-03-19 09:13:01 +00005570 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005571
5572 while (fgets(line, sizeof(line), procpt)) {
5573 if (sscanf (line, " %d %d %d %[^\n ]",
5574 &ma, &mi, &sz, ptname) != 4)
5575 continue;
5576 for (s = ptname; *s; s++);
5577 if (isdigit(s[-1]))
5578 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005579 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005580 try(devname, 0);
5581 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005582#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005583 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005584#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005585}
5586
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005587#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005588static void
5589unknown_command(int c) {
5590 printf(_("%c: unknown command\n"), c);
5591}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005592#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005593
5594int fdisk_main(int argc, char **argv) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005595 int c;
5596#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5597 int optl = 0;
5598#endif
5599#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5600 int opts = 0;
5601#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005602 /*
5603 * Calls:
5604 * fdisk -v
5605 * fdisk -l [-b sectorsize] [-u] device ...
5606 * fdisk -s [partition] ...
5607 * fdisk [-b sectorsize] [-u] device
5608 *
5609 * Options -C, -H, -S set the geometry.
5610 *
5611 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005612 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5613#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5614 "s"
5615#endif
5616 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005617 switch (c) {
5618 case 'b':
5619 /* Ugly: this sector size is really per device,
5620 so cannot be combined with multiple disks,
5621 and te same goes for the C/H/S options.
5622 */
5623 sector_size = atoi(optarg);
5624 if (sector_size != 512 && sector_size != 1024 &&
5625 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005626 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005627 sector_offset = 2;
5628 user_set_sector_size = 1;
5629 break;
5630 case 'C':
5631 user_cylinders = atoi(optarg);
5632 break;
5633 case 'H':
5634 user_heads = atoi(optarg);
5635 if (user_heads <= 0 || user_heads >= 256)
5636 user_heads = 0;
5637 break;
5638 case 'S':
5639 user_sectors = atoi(optarg);
5640 if (user_sectors <= 0 || user_sectors >= 64)
5641 user_sectors = 0;
5642 break;
5643 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005644#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005645 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005646#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005647 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005648#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005649 case 's':
5650 opts = 1;
5651 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005652#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005653 case 'u':
5654 display_in_cyl_units = 0;
5655 break;
5656 case 'V':
5657 case 'v':
5658 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5659 return 0;
5660 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005661 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005662 }
5663 }
5664
5665#if 0
5666 printf(_("This kernel finds the sector size itself - "
5667 "-b option ignored\n"));
5668#else
5669 if (user_set_sector_size && argc-optind != 1)
5670 printf(_("Warning: the -b (set sector size) option should"
5671 " be used with one specified device\n"));
5672#endif
5673
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005674#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005675 if (optl) {
5676 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005677#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005678 type_open = O_RDONLY;
5679 if (argc > optind) {
5680 int k;
5681#if __GNUC__
5682 /* avoid gcc warning:
5683 variable `k' might be clobbered by `longjmp' */
5684 (void)&k;
5685#endif
5686 listing = 1;
5687 for (k=optind; k<argc; k++)
5688 try(argv[k], 1);
5689 } else {
5690 /* we no longer have default device names */
5691 /* but, we can use /proc/partitions instead */
5692 tryprocpt();
5693 }
5694 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005695#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005696 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005697#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005698
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005699#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005700 if (opts) {
5701 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005702 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005703
5704 nowarn = 1;
5705 type_open = O_RDONLY;
5706
5707 opts = argc - optind;
5708 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005709 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005710
5711 for (j = optind; j < argc; j++) {
5712 disk_device = argv[j];
5713 if ((fd = open(disk_device, type_open)) < 0)
5714 fdisk_fatal(unable_to_open);
5715 if (ioctl(fd, BLKGETSIZE, &size))
5716 fdisk_fatal(ioctl_error);
5717 close(fd);
5718 if (opts == 1)
5719 printf("%ld\n", size/2);
5720 else
5721 printf("%s: %ld\n", argv[j], size/2);
5722 }
5723 return 0;
5724 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005725#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005726
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005727#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005728 if (argc-optind == 1)
5729 disk_device = argv[optind];
5730 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005731 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005732
5733 get_boot(fdisk);
5734
5735#ifdef CONFIG_FEATURE_OSF_LABEL
5736 if (osf_label) {
5737 /* OSF label, and no DOS label */
5738 printf(_("Detected an OSF/1 disklabel on %s, entering "
5739 "disklabel mode.\n"),
5740 disk_device);
5741 bselect();
5742 osf_label = 0;
5743 /* If we return we may want to make an empty DOS label? */
5744 }
5745#endif
5746
5747 while (1) {
5748 putchar('\n');
5749 c = tolower(read_char(_("Command (m for help): ")));
5750 switch (c) {
5751 case 'a':
5752 if (dos_label)
5753 toggle_active(get_partition(1, partitions));
5754#ifdef CONFIG_FEATURE_SUN_LABEL
5755 else if (sun_label)
5756 toggle_sunflags(get_partition(1, partitions),
5757 0x01);
5758#endif
5759#ifdef CONFIG_FEATURE_SGI_LABEL
5760 else if (sgi_label)
5761 sgi_set_bootpartition(
5762 get_partition(1, partitions));
5763#endif
5764 else
5765 unknown_command(c);
5766 break;
5767 case 'b':
5768#ifdef CONFIG_FEATURE_SGI_LABEL
5769 if (sgi_label) {
5770 printf(_("\nThe current boot file is: %s\n"),
5771 sgi_get_bootfile());
5772 if (read_chars(_("Please enter the name of the "
5773 "new boot file: ")) == '\n')
5774 printf(_("Boot file unchanged\n"));
5775 else
5776 sgi_set_bootfile(line_ptr);
5777 } else
5778#endif
5779#ifdef CONFIG_FEATURE_OSF_LABEL
5780 bselect();
5781#endif
5782 break;
5783 case 'c':
5784 if (dos_label)
5785 toggle_dos_compatibility_flag();
5786#ifdef CONFIG_FEATURE_SUN_LABEL
5787 else if (sun_label)
5788 toggle_sunflags(get_partition(1, partitions),
5789 0x10);
5790#endif
5791#ifdef CONFIG_FEATURE_SGI_LABEL
5792 else if (sgi_label)
5793 sgi_set_swappartition(
5794 get_partition(1, partitions));
5795#endif
5796 else
5797 unknown_command(c);
5798 break;
5799 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005800 {
Eric Andersen040f4402003-07-30 08:40:37 +00005801 int j;
5802#ifdef CONFIG_FEATURE_SGI_LABEL
5803 /* If sgi_label then don't use get_existing_partition,
5804 let the user select a partition, since
5805 get_existing_partition() only works for Linux-like
5806 partition tables */
5807 if (!sgi_label) {
5808 j = get_existing_partition(1, partitions);
5809 } else {
5810 j = get_partition(1, partitions);
5811 }
5812#else
5813 j = get_existing_partition(1, partitions);
5814#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005815 if (j >= 0)
5816 delete_partition(j);
5817 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005818 break;
5819 case 'i':
5820#ifdef CONFIG_FEATURE_SGI_LABEL
5821 if (sgi_label)
5822 create_sgiinfo();
5823 else
5824#endif
5825 unknown_command(c);
5826 case 'l':
5827 list_types(get_sys_types());
5828 break;
5829 case 'm':
5830 menu();
5831 break;
5832 case 'n':
5833 new_partition();
5834 break;
5835 case 'o':
5836 create_doslabel();
5837 break;
5838 case 'p':
5839 list_table(0);
5840 break;
5841 case 'q':
5842 close(fd);
5843 printf("\n");
5844 return 0;
5845 case 's':
5846#ifdef CONFIG_FEATURE_SUN_LABEL
5847 create_sunlabel();
5848#endif
5849 break;
5850 case 't':
5851 change_sysid();
5852 break;
5853 case 'u':
5854 change_units();
5855 break;
5856 case 'v':
5857 verify();
5858 break;
5859 case 'w':
5860 write_table(); /* does not return */
5861 break;
5862#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5863 case 'x':
5864#ifdef CONFIG_FEATURE_SGI_LABEL
5865 if (sgi_label) {
5866 fprintf(stderr,
5867 _("\n\tSorry, no experts menu for SGI "
5868 "partition tables available.\n\n"));
5869 } else
5870#endif
5871
5872 xselect();
5873 break;
5874#endif
5875 default:
5876 unknown_command(c);
5877 menu();
5878 }
5879 }
5880 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005881#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005882}