blob: b9e875f41dab5f23910997e5ea303d29d503b1c6 [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 *
5 * This program is free software. You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation: either version 1 or
8 * (at your option) any later version.
9 *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000010 * Vladimir Oleynik <dzo@simtreas.ru> 2001,2002 Busybox port
11 */
12
Eric Andersen99a75d12003-08-08 20:04:56 +000013#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014
15#define PROC_PARTITIONS "/proc/partitions"
16
17#include <sys/types.h>
18#include <sys/stat.h> /* stat */
19#include <ctype.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <setjmp.h>
27#include <assert.h> /* assert */
28#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000029#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030#include <sys/ioctl.h>
31#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000032#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000033
Eric Andersenacd244a2002-12-11 03:49:33 +000034#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
35
36/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000037#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000038
39#include <sys/utsname.h>
40
41#include "busybox.h"
42
43#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
44
45#define DKTYPENAMES
46
47#define _(Text) Text
48
49#define BLKRRPART _IO(0x12,95) /* re-read partition table */
50#define BLKGETSIZE _IO(0x12,96) /* return device size */
51#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
52#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000053
54/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000055 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000056#undef _IOR
57#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000058#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000059
60/*
61 fdisk.h
62*/
63
64#define DEFAULT_SECTOR_SIZE 512
65#define MAX_SECTOR_SIZE 2048
66#define SECTOR_SIZE 512 /* still used in BSD code */
67#define MAXIMUM_PARTS 60
68
69#define ACTIVE_FLAG 0x80
70
71#define EXTENDED 0x05
72#define WIN98_EXTENDED 0x0f
73#define LINUX_PARTITION 0x81
74#define LINUX_SWAP 0x82
75#define LINUX_NATIVE 0x83
76#define LINUX_EXTENDED 0x85
77#define LINUX_LVM 0x8e
78#define LINUX_RAID 0xfd
79
80#define SUNOS_SWAP 3
81#define WHOLE_DISK 5
82
83#define IS_EXTENDED(i) \
84 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
85
86#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
87
88#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
89#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
90
Eric Andersen7495b0d2004-02-06 05:26:58 +000091#ifdef CONFIG_FEATURE_SUN_LABEL
92#define SCSI_IOCTL_GET_IDLUN 0x5382
93#endif
94
Eric Andersend3652bf2003-08-06 09:07:37 +000095
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000096/* including <linux/hdreg.h> also fails */
97struct hd_geometry {
98 unsigned char heads;
99 unsigned char sectors;
100 unsigned short cylinders;
101 unsigned long start;
102};
103
104#define HDIO_GETGEO 0x0301 /* get device geometry */
105
106
107struct systypes {
108 const unsigned char *name;
109};
110
Eric Andersen040f4402003-07-30 08:40:37 +0000111static uint sector_size = DEFAULT_SECTOR_SIZE,
112 user_set_sector_size,
113 sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000114
115/*
116 * Raw disk label. For DOS-type partition tables the MBR,
117 * with descriptions of the primary partitions.
118 */
119static char MBRbuffer[MAX_SECTOR_SIZE];
120
121#ifdef CONFIG_FEATURE_SUN_LABEL
122static int sun_label; /* looking at sun disklabel */
123#else
124#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000125#endif
126#ifdef CONFIG_FEATURE_SGI_LABEL
127static int sgi_label; /* looking at sgi disklabel */
128#else
129#define sgi_label 0
130#endif
131#ifdef CONFIG_FEATURE_AIX_LABEL
132static int aix_label; /* looking at aix disklabel */
133#else
134#define aix_label 0
135#endif
136#ifdef CONFIG_FEATURE_OSF_LABEL
137static int osf_label; /* looking at OSF/1 disklabel */
138static int possibly_osf_label;
139#else
140#define osf_label 0
141#endif
142
143#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
144
145static uint heads, sectors, cylinders;
146static void update_units(void);
147
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000148
149/*
150 * return partition name - uses static storage unless buf is supplied
151 */
152static const char *
153partname(const char *dev, int pno, int lth) {
154 static char buffer[80];
155 const char *p;
156 int w, wp;
157 int bufsiz;
158 char *bufp;
159
160 bufp = buffer;
161 bufsiz = sizeof(buffer);
162
163 w = strlen(dev);
164 p = "";
165
166 if (isdigit(dev[w-1]))
167 p = "p";
168
169 /* devfs kludge - note: fdisk partition names are not supposed
170 to equal kernel names, so there is no reason to do this */
171 if (strcmp (dev + w - 4, "disc") == 0) {
172 w -= 4;
173 p = "part";
174 }
175
176 wp = strlen(p);
177
178 if (lth) {
179 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
180 lth-wp-2, w, dev, p, pno);
181 } else {
182 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
183 }
184 return bufp;
185}
186
187struct partition {
188 unsigned char boot_ind; /* 0x80 - active */
189 unsigned char head; /* starting head */
190 unsigned char sector; /* starting sector */
191 unsigned char cyl; /* starting cylinder */
192 unsigned char sys_ind; /* What partition type */
193 unsigned char end_head; /* end head */
194 unsigned char end_sector; /* end sector */
195 unsigned char end_cyl; /* end cylinder */
196 unsigned char start4[4]; /* starting sector counting from 0 */
197 unsigned char size4[4]; /* nr of sectors in partition */
Eric Andersen7495b0d2004-02-06 05:26:58 +0000198} __attribute__((__packed__));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000199
200enum failure {
201 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
202 unable_to_write
203};
204
205enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
206
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000207static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000208static int fd; /* the disk */
209static int partitions = 4; /* maximum partition + 1 */
210static uint display_in_cyl_units = 1;
211static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000212#ifdef CONFIG_FEATURE_FDISK_WRITABLE
213static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000214static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000215static void reread_partition_table(int leave);
216static void delete_partition(int i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000217static int get_partition(int warn, int max);
218static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000219static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000220#endif
221static const char *partition_type(unsigned char type);
222static void fdisk_fatal(enum failure why) __attribute__ ((noreturn));
223static void get_geometry(void);
224static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000225
226#define PLURAL 0
227#define SINGULAR 1
228
229#define hex_val(c) ({ \
230 char _c = (c); \
231 isdigit(_c) ? _c - '0' : \
232 tolower(_c) + 10 - 'a'; \
233 })
234
235
236#define LINE_LENGTH 800
237#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
238 (n) * sizeof(struct partition)))
239#define sector(s) ((s) & 0x3f)
240#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
241
242#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
243 ((h) + heads * cylinder(s,c)))
244#define set_hsc(h,s,c,sector) { \
245 s = sector % sectors + 1; \
246 sector /= sectors; \
247 h = sector % heads; \
248 sector /= heads; \
249 c = sector & 0xff; \
250 s |= (sector >> 2) & 0xc0; \
251 }
252
253
254static unsigned int get_start_sect(const struct partition *p);
255static unsigned int get_nr_sects(const struct partition *p);
256
257/*
258 * per partition table entry data
259 *
260 * The four primary partitions have the same sectorbuffer (MBRbuffer)
261 * and have NULL ext_pointer.
262 * Each logical partition table entry has two pointers, one for the
263 * partition and one link to the next one.
264 */
265static struct pte {
266 struct partition *part_table; /* points into sectorbuffer */
267 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000268#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000269 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000270#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000271 uint offset; /* disk sector number */
272 char *sectorbuffer; /* disk sector contents */
273} ptes[MAXIMUM_PARTS];
274
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000275
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000276#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000277static void
278set_all_unchanged(void) {
279 int i;
280
281 for (i = 0; i < MAXIMUM_PARTS; i++)
282 ptes[i].changed = 0;
283}
284
285static void
286set_changed(int i) {
287 ptes[i].changed = 1;
288}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000289#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000290
291#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
292static struct partition *
293get_part_table(int i) {
294 return ptes[i].part_table;
295}
296#endif
297
298static const char *
299str_units(int n) { /* n==1: use singular */
300 if (n == 1)
301 return display_in_cyl_units ? _("cylinder") : _("sector");
302 else
303 return display_in_cyl_units ? _("cylinders") : _("sectors");
304}
305
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000306static int
307valid_part_table_flag(const unsigned char *b) {
308 return (b[510] == 0x55 && b[511] == 0xaa);
309}
310
311#ifdef CONFIG_FEATURE_FDISK_WRITABLE
312static char line_buffer[LINE_LENGTH];
313
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000314/* read line; return 0 or first char */
315static int
316read_line(void)
317{
318 static int got_eof = 0;
319
320 fflush (stdout); /* requested by niles@scyld.com */
321 line_ptr = line_buffer;
322 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
323 if (feof(stdin))
324 got_eof++; /* user typed ^D ? */
325 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000326 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
327 exit(1);
328 }
329 return 0;
330 }
331 while (*line_ptr && !isgraph(*line_ptr))
332 line_ptr++;
333 return *line_ptr;
334}
335
336static char
337read_char(const char *mesg)
338{
339 do {
340 fputs(mesg, stdout);
341 } while (!read_line());
342 return *line_ptr;
343}
344
345static char
346read_chars(const char *mesg)
347{
348 fputs(mesg, stdout);
349 if (!read_line()) {
350 *line_ptr = '\n';
351 line_ptr[1] = 0;
352 }
353 return *line_ptr;
354}
355
356static int
357read_hex(const struct systypes *sys)
358{
359 int hex;
360
361 while (1)
362 {
363 read_char(_("Hex code (type L to list codes): "));
364 if (*line_ptr == 'l' || *line_ptr == 'L')
365 list_types(sys);
366 else if (isxdigit (*line_ptr))
367 {
368 hex = 0;
369 do
370 hex = hex << 4 | hex_val(*line_ptr++);
371 while (isxdigit(*line_ptr));
372 return hex;
373 }
374 }
375}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000376#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000377
378#ifdef CONFIG_FEATURE_AIX_LABEL
379/*
380 * Copyright (C) Andreas Neuper, Sep 1998.
381 * This file may be redistributed under
382 * the terms of the GNU Public License.
383 */
384
385typedef struct {
386 unsigned int magic; /* expect AIX_LABEL_MAGIC */
387 unsigned int fillbytes1[124];
388 unsigned int physical_volume_id;
389 unsigned int fillbytes2[124];
390} aix_partition;
391
392#define AIX_LABEL_MAGIC 0xc9c2d4c1
393#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
394#define AIX_INFO_MAGIC 0x00072959
395#define AIX_INFO_MAGIC_SWAPPED 0x59290700
396
397#define aixlabel ((aix_partition *)MBRbuffer)
398
399
400/*
401 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000402 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
403 * Internationalization
404 *
405 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
406 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000407*/
408
409static int aix_other_endian;
410static short aix_volumes=1;
411
412/*
413 * only dealing with free blocks here
414 */
415
416static void
417aix_info( void ) {
418 puts(
419 _("\n\tThere is a valid AIX label on this disk.\n"
420 "\tUnfortunately Linux cannot handle these\n"
421 "\tdisks at the moment. Nevertheless some\n"
422 "\tadvice:\n"
423 "\t1. fdisk will destroy its contents on write.\n"
424 "\t2. Be sure that this disk is NOT a still vital\n"
425 "\t part of a volume group. (Otherwise you may\n"
426 "\t erase the other disks as well, if unmirrored.)\n"
427 "\t3. Before deleting this physical volume be sure\n"
428 "\t to remove the disk logically from your AIX\n"
429 "\t machine. (Otherwise you become an AIXpert).")
430 );
431}
432
433static void
434aix_nolabel( void )
435{
436 aixlabel->magic = 0;
437 aix_label = 0;
438 partitions = 4;
439 memset( MBRbuffer, 0, sizeof(MBRbuffer) ); /* avoid fdisk cores */
440 return;
441}
442
443static int
444check_aix_label( void )
445{
446 if (aixlabel->magic != AIX_LABEL_MAGIC &&
447 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
448 aix_label = 0;
449 aix_other_endian = 0;
450 return 0;
451 }
452 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
453 update_units();
454 aix_label = 1;
455 partitions= 1016;
456 aix_volumes = 15;
457 aix_info();
458 aix_nolabel(); /* %% */
459 aix_label = 1; /* %% */
460 return 1;
461}
462#endif /* AIX_LABEL */
463
464#ifdef CONFIG_FEATURE_OSF_LABEL
465/*
466 * Copyright (c) 1987, 1988 Regents of the University of California.
467 * All rights reserved.
468 *
469 * Redistribution and use in source and binary forms, with or without
470 * modification, are permitted provided that the following conditions
471 * are met:
472 * 1. Redistributions of source code must retain the above copyright
473 * notice, this list of conditions and the following disclaimer.
474 * 2. Redistributions in binary form must reproduce the above copyright
475 * notice, this list of conditions and the following disclaimer in the
476 * documentation and/or other materials provided with the distribution.
477 * 3. All advertising materials mentioning features or use of this software
478 * must display the following acknowledgement:
479 * This product includes software developed by the University of
480 * California, Berkeley and its contributors.
481 * 4. Neither the name of the University nor the names of its contributors
482 * may be used to endorse or promote products derived from this software
483 * without specific prior written permission.
484 *
485 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
486 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
487 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
488 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
489 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
490 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
491 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
492 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
493 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
494 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
495 * SUCH DAMAGE.
496 */
497
498
499#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000500#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000501#endif
502
503#ifndef BSD_MAXPARTITIONS
504#define BSD_MAXPARTITIONS 16
505#endif
506
507#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
508
509#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
510#define BSD_LABELSECTOR 1
511#define BSD_LABELOFFSET 0
512#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
513#define BSD_LABELSECTOR 0
514#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000515#elif defined (__s390__) || defined (__s390x__)
516#define BSD_LABELSECTOR 1
517#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000518#else
519#error unknown architecture
520#endif
521
522#define BSD_BBSIZE 8192 /* size of boot area, with label */
523#define BSD_SBSIZE 8192 /* max size of fs superblock */
524
525struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000526 uint32_t d_magic; /* the magic number */
527 int16_t d_type; /* drive type */
528 int16_t d_subtype; /* controller/d_type specific */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000529 char d_typename[16]; /* type name, e.g. "eagle" */
530 char d_packname[16]; /* pack identifier */
531 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000532 uint32_t d_secsize; /* # of bytes per sector */
533 uint32_t d_nsectors; /* # of data sectors per track */
534 uint32_t d_ntracks; /* # of tracks per cylinder */
535 uint32_t d_ncylinders; /* # of data cylinders per unit */
536 uint32_t d_secpercyl; /* # of data sectors per cylinder */
537 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000538 /*
539 * Spares (bad sector replacements) below
540 * are not counted in d_nsectors or d_secpercyl.
541 * Spare sectors are assumed to be physical sectors
542 * which occupy space at the end of each track and/or cylinder.
543 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000544 uint16_t d_sparespertrack; /* # of spare sectors per track */
545 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000546 /*
547 * Alternate cylinders include maintenance, replacement,
548 * configuration description areas, etc.
549 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000550 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000551
552 /* hardware characteristics: */
553 /*
554 * d_interleave, d_trackskew and d_cylskew describe perturbations
555 * in the media format used to compensate for a slow controller.
556 * Interleave is physical sector interleave, set up by the formatter
557 * or controller when formatting. When interleaving is in use,
558 * logically adjacent sectors are not physically contiguous,
559 * but instead are separated by some number of sectors.
560 * It is specified as the ratio of physical sectors traversed
561 * per logical sector. Thus an interleave of 1:1 implies contiguous
562 * layout, while 2:1 implies that logical sector 0 is separated
563 * by one sector from logical sector 1.
564 * d_trackskew is the offset of sector 0 on track N
565 * relative to sector 0 on track N-1 on the same cylinder.
566 * Finally, d_cylskew is the offset of sector 0 on cylinder N
567 * relative to sector 0 on cylinder N-1.
568 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000569 uint16_t d_rpm; /* rotational speed */
570 uint16_t d_interleave; /* hardware sector interleave */
571 uint16_t d_trackskew; /* sector 0 skew, per track */
572 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
573 uint32_t d_headswitch; /* head switch time, usec */
574 uint32_t d_trkseek; /* track-to-track seek, usec */
575 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000576#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000577 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000578#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000579 uint32_t d_spare[NSPARE]; /* reserved for future use */
580 uint32_t d_magic2; /* the magic number (again) */
581 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000582 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000583 uint16_t d_npartitions; /* number of partitions in following */
584 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
585 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000586 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000587 uint32_t p_size; /* number of sectors in partition */
588 uint32_t p_offset; /* starting sector */
589 uint32_t p_fsize; /* filesystem basic fragment size */
590 uint8_t p_fstype; /* filesystem type, see below */
591 uint8_t p_frag; /* filesystem fragments per block */
592 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000593 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
594};
595
596/* d_type values: */
597#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
598#define BSD_DTYPE_MSCP 2 /* MSCP */
599#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
600#define BSD_DTYPE_SCSI 4 /* SCSI */
601#define BSD_DTYPE_ESDI 5 /* ESDI interface */
602#define BSD_DTYPE_ST506 6 /* ST506 etc. */
603#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
604#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
605#define BSD_DTYPE_FLOPPY 10 /* floppy */
606
607/* d_subtype values: */
608#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
609#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
610#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
611
612#ifdef DKTYPENAMES
613static const char * const xbsd_dktypenames[] = {
614 "unknown",
615 "SMD",
616 "MSCP",
617 "old DEC",
618 "SCSI",
619 "ESDI",
620 "ST506",
621 "HP-IB",
622 "HP-FL",
623 "type 9",
624 "floppy",
625 0
626};
627#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
628#endif
629
630/*
631 * Filesystem type and version.
632 * Used to interpret other filesystem-specific
633 * per-partition information.
634 */
635#define BSD_FS_UNUSED 0 /* unused */
636#define BSD_FS_SWAP 1 /* swap */
637#define BSD_FS_V6 2 /* Sixth Edition */
638#define BSD_FS_V7 3 /* Seventh Edition */
639#define BSD_FS_SYSV 4 /* System V */
640#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
641#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
642#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
643#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
644#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
645#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
646#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
647#define BSD_FS_ISOFS BSD_FS_ISO9660
648#define BSD_FS_BOOT 13 /* partition contains bootstrap */
649#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
650#define BSD_FS_HFS 15 /* Macintosh HFS */
651#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
652
653/* this is annoying, but it's also the way it is :-( */
654#ifdef __alpha__
655#define BSD_FS_EXT2 8 /* ext2 file system */
656#else
657#define BSD_FS_MSDOS 8 /* MS-DOS file system */
658#endif
659
660#ifdef DKTYPENAMES
661static const struct systypes xbsd_fstypes[] = {
662/* BSD_FS_UNUSED */ {"\x00" "unused"},
663/* BSD_FS_SWAP */ {"\x01" "swap"},
664/* BSD_FS_V6 */ {"\x02" "Version 6"},
665/* BSD_FS_V7 */ {"\x03" "Version 7"},
666/* BSD_FS_SYSV */ {"\x04" "System V"},
667/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
668/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
669/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
670#ifdef __alpha__
671/* BSD_FS_EXT2 */ {"\x08" "ext2"},
672#else
673/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
674#endif
675/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
676/* BSD_FS_OTHER */ {"\x0a" "unknown"},
677/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
678/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
679/* BSD_FS_BOOT */ {"\x0d" "boot"},
680/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
681/* BSD_FS_HFS */ {"\x0f" "HFS"},
682/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
683 { NULL }
684};
685#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
686
687#endif
688
689/*
690 * flags shared by various drives:
691 */
692#define BSD_D_REMOVABLE 0x01 /* removable media */
693#define BSD_D_ECC 0x02 /* supports ECC */
694#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
695#define BSD_D_RAMDISK 0x08 /* disk emulator */
696#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
697#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
698
699#endif /* OSF_LABEL */
700
701/*
702 * Copyright (C) Andreas Neuper, Sep 1998.
703 * This file may be modified and redistributed under
704 * the terms of the GNU Public License.
705 */
706
707struct device_parameter { /* 48 bytes */
708 unsigned char skew;
709 unsigned char gap1;
710 unsigned char gap2;
711 unsigned char sparecyl;
712 unsigned short pcylcount;
713 unsigned short head_vol0;
714 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
715 unsigned char cmd_tag_queue_depth;
716 unsigned char unused0;
717 unsigned short unused1;
718 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
719 unsigned short bytes;
720 unsigned short ilfact;
721 unsigned int flags; /* controller flags */
722 unsigned int datarate;
723 unsigned int retries_on_error;
724 unsigned int ms_per_word;
725 unsigned short xylogics_gap1;
726 unsigned short xylogics_syncdelay;
727 unsigned short xylogics_readdelay;
728 unsigned short xylogics_gap2;
729 unsigned short xylogics_readgate;
730 unsigned short xylogics_writecont;
731};
732
733#define SGI_VOLHDR 0x00
734/* 1 and 2 were used for drive types no longer supported by SGI */
735#define SGI_SWAP 0x03
736/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
737#define SGI_VOLUME 0x06
738#define SGI_EFS 0x07
739#define SGI_LVOL 0x08
740#define SGI_RLVOL 0x09
741#define SGI_XFS 0x0a
742#define SGI_XFSLOG 0x0b
743#define SGI_XLV 0x0c
744#define SGI_XVM 0x0d
745#define ENTIRE_DISK SGI_VOLUME
746/*
747 * controller flags
748 */
749#define SECTOR_SLIP 0x01
750#define SECTOR_FWD 0x02
751#define TRACK_FWD 0x04
752#define TRACK_MULTIVOL 0x08
753#define IGNORE_ERRORS 0x10
754#define RESEEK 0x20
755#define ENABLE_CMDTAGQ 0x40
756
757typedef struct {
758 unsigned int magic; /* expect SGI_LABEL_MAGIC */
759 unsigned short boot_part; /* active boot partition */
760 unsigned short swap_part; /* active swap partition */
761 unsigned char boot_file[16]; /* name of the bootfile */
762 struct device_parameter devparam; /* 1 * 48 bytes */
763 struct volume_directory { /* 15 * 16 bytes */
764 unsigned char vol_file_name[8]; /* a character array */
765 unsigned int vol_file_start; /* number of logical block */
766 unsigned int vol_file_size; /* number of bytes */
767 } directory[15];
768 struct sgi_partition { /* 16 * 12 bytes */
769 unsigned int num_sectors; /* number of blocks */
770 unsigned int start_sector; /* must be cylinder aligned */
771 unsigned int id;
772 } partitions[16];
773 unsigned int csum;
774 unsigned int fillbytes;
775} sgi_partition;
776
777typedef struct {
778 unsigned int magic; /* looks like a magic number */
779 unsigned int a2;
780 unsigned int a3;
781 unsigned int a4;
782 unsigned int b1;
783 unsigned short b2;
784 unsigned short b3;
785 unsigned int c[16];
786 unsigned short d[3];
787 unsigned char scsi_string[50];
788 unsigned char serial[137];
789 unsigned short check1816;
790 unsigned char installer[225];
791} sgiinfo;
792
793#define SGI_LABEL_MAGIC 0x0be5a941
794#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
795#define SGI_INFO_MAGIC 0x00072959
796#define SGI_INFO_MAGIC_SWAPPED 0x59290700
797#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000798 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000799#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000800 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000801
802#define sgilabel ((sgi_partition *)MBRbuffer)
803#define sgiparam (sgilabel->devparam)
804
805typedef struct {
806 unsigned char info[128]; /* Informative text string */
807 unsigned char spare0[14];
808 struct sun_info {
809 unsigned char spare1;
810 unsigned char id;
811 unsigned char spare2;
812 unsigned char flags;
813 } infos[8];
814 unsigned char spare1[246]; /* Boot information etc. */
815 unsigned short rspeed; /* Disk rotational speed */
816 unsigned short pcylcount; /* Physical cylinder count */
817 unsigned short sparecyl; /* extra sects per cylinder */
818 unsigned char spare2[4]; /* More magic... */
819 unsigned short ilfact; /* Interleave factor */
820 unsigned short ncyl; /* Data cylinder count */
821 unsigned short nacyl; /* Alt. cylinder count */
822 unsigned short ntrks; /* Tracks per cylinder */
823 unsigned short nsect; /* Sectors per track */
824 unsigned char spare3[4]; /* Even more magic... */
825 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000826 uint32_t start_cylinder;
827 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000828 } partitions[8];
829 unsigned short magic; /* Magic number */
830 unsigned short csum; /* Label xor'd checksum */
831} sun_partition;
832
Eric Andersen040f4402003-07-30 08:40:37 +0000833
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000834#define SUN_LABEL_MAGIC 0xDABE
835#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
836#define sunlabel ((sun_partition *)MBRbuffer)
837#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000838 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000839#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000840 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000841
Eric Andersend3652bf2003-08-06 09:07:37 +0000842
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000843#ifdef CONFIG_FEATURE_OSF_LABEL
844/*
845 Changes:
846 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
847
848 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
849 support for OSF/1 disklabels on Alpha.
850 Also fixed unaligned accesses in alpha_bootblock_checksum()
851*/
852
853#define FREEBSD_PARTITION 0xa5
854#define NETBSD_PARTITION 0xa9
855
856static void xbsd_delete_part (void);
857static void xbsd_new_part (void);
858static void xbsd_write_disklabel (void);
859static int xbsd_create_disklabel (void);
860static void xbsd_edit_disklabel (void);
861static void xbsd_write_bootstrap (void);
862static void xbsd_change_fstype (void);
863static int xbsd_get_part_index (int max);
864static int xbsd_check_new_partition (int *i);
865static void xbsd_list_types (void);
866static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
867static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d,
868 int pindex);
869static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
870static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
871
872#if defined (__alpha__)
873static void alpha_bootblock_checksum (char *boot);
874#endif
875
876#if !defined (__alpha__)
877static int xbsd_translate_fstype (int linux_type);
878static void xbsd_link_part (void);
879static struct partition *xbsd_part;
880static int xbsd_part_index;
881#endif
882
883#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000884/* We access this through a uint64_t * when checksumming */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000885static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
886#else
887static char disklabelbuffer[BSD_BBSIZE];
888#endif
889
890static struct xbsd_disklabel xbsd_dlabel;
891
892#define bsd_cround(n) \
893 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
894
895/*
896 * Test whether the whole disk has BSD disk label magic.
897 *
898 * Note: often reformatting with DOS-type label leaves the BSD magic,
899 * so this does not mean that there is a BSD disk label.
900 */
901static int
902check_osf_label(void) {
903 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
904 return 0;
905 return 1;
906}
907
908static void xbsd_print_disklabel(int);
909
910static int
Glenn L McGrath35631a62002-12-08 11:51:05 +0000911btrydev (const char * dev) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000912 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
913 return -1;
914 printf(_("\nBSD label for device: %s\n"), dev);
915 xbsd_print_disklabel (0);
916 return 0;
917}
918
919static void
920bmenu (void) {
921 puts (_("Command action"));
922 puts (_("\td\tdelete a BSD partition"));
923 puts (_("\te\tedit drive data"));
924 puts (_("\ti\tinstall bootstrap"));
925 puts (_("\tl\tlist known filesystem types"));
926 puts (_("\tm\tprint this menu"));
927 puts (_("\tn\tadd a new BSD partition"));
928 puts (_("\tp\tprint BSD partition table"));
929 puts (_("\tq\tquit without saving changes"));
930 puts (_("\tr\treturn to main menu"));
931 puts (_("\ts\tshow complete disklabel"));
932 puts (_("\tt\tchange a partition's filesystem id"));
933 puts (_("\tu\tchange units (cylinders/sectors)"));
934 puts (_("\tw\twrite disklabel to disk"));
935#if !defined (__alpha__)
936 puts (_("\tx\tlink BSD partition to non-BSD partition"));
937#endif
938}
939
940#if !defined (__alpha__)
941static int
942hidden(int type) {
943 return type ^ 0x10;
944}
945
946static int
947is_bsd_partition_type(int type) {
948 return (type == FREEBSD_PARTITION ||
949 type == hidden(FREEBSD_PARTITION) ||
950 type == NETBSD_PARTITION ||
951 type == hidden(NETBSD_PARTITION));
952}
953#endif
954
955static void
956bselect (void) {
957#if !defined (__alpha__)
958 int t, ss;
959 struct partition *p;
960
961 for (t=0; t<4; t++) {
962 p = get_part_table(t);
963 if (p && is_bsd_partition_type(p->sys_ind)) {
964 xbsd_part = p;
965 xbsd_part_index = t;
966 ss = get_start_sect(xbsd_part);
967 if (ss == 0) {
968 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
969 partname(disk_device, t+1, 0));
970 return;
971 }
972 printf (_("Reading disklabel of %s at sector %d.\n"),
973 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
974 if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
975 if (xbsd_create_disklabel () == 0)
976 return;
977 break;
978 }
979 }
980
981 if (t == 4) {
982 printf (_("There is no *BSD partition on %s.\n"), disk_device);
983 return;
984 }
985
986#elif defined (__alpha__)
987
988 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
989 if (xbsd_create_disklabel () == 0)
990 exit ( EXIT_SUCCESS );
991
992#endif
993
994 while (1) {
995 putchar ('\n');
996 switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
997 case 'd':
998 xbsd_delete_part ();
999 break;
1000 case 'e':
1001 xbsd_edit_disklabel ();
1002 break;
1003 case 'i':
1004 xbsd_write_bootstrap ();
1005 break;
1006 case 'l':
1007 xbsd_list_types ();
1008 break;
1009 case 'n':
1010 xbsd_new_part ();
1011 break;
1012 case 'p':
1013 xbsd_print_disklabel (0);
1014 break;
1015 case 'q':
1016 close (fd);
1017 exit ( EXIT_SUCCESS );
1018 case 'r':
1019 return;
1020 case 's':
1021 xbsd_print_disklabel (1);
1022 break;
1023 case 't':
1024 xbsd_change_fstype ();
1025 break;
1026 case 'u':
1027 change_units();
1028 break;
1029 case 'w':
1030 xbsd_write_disklabel ();
1031 break;
1032#if !defined (__alpha__)
1033 case 'x':
1034 xbsd_link_part ();
1035 break;
1036#endif
1037 default:
1038 bmenu ();
1039 break;
1040 }
1041 }
1042}
1043
1044static void
1045xbsd_delete_part (void)
1046{
1047 int i;
1048
1049 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1050 xbsd_dlabel.d_partitions[i].p_size = 0;
1051 xbsd_dlabel.d_partitions[i].p_offset = 0;
1052 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1053 if (xbsd_dlabel.d_npartitions == i + 1)
1054 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1055 xbsd_dlabel.d_npartitions--;
1056}
1057
1058static void
1059xbsd_new_part (void)
1060{
1061 uint begin, end;
1062 char mesg[256];
1063 int i;
1064
1065 if (!xbsd_check_new_partition (&i))
1066 return;
1067
1068#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1069 begin = get_start_sect(xbsd_part);
1070 end = begin + get_nr_sects(xbsd_part) - 1;
1071#else
1072 begin = 0;
1073 end = xbsd_dlabel.d_secperunit - 1;
1074#endif
1075
1076 snprintf (mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1077 begin = read_int (bsd_cround (begin), bsd_cround (begin), bsd_cround (end),
1078 0, mesg);
1079
1080 if (display_in_cyl_units)
1081 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
1082
1083 snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1084 str_units(SINGULAR));
1085 end = read_int (bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1086 bsd_cround (begin), mesg);
1087
1088 if (display_in_cyl_units)
1089 end = end * xbsd_dlabel.d_secpercyl - 1;
1090
1091 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1092 xbsd_dlabel.d_partitions[i].p_offset = begin;
1093 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1094}
1095
1096static void
1097xbsd_print_disklabel (int show_all) {
1098 struct xbsd_disklabel *lp = &xbsd_dlabel;
1099 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001100 int i, j;
1101
1102 if (show_all) {
1103#if defined (__alpha__)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001104 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001105#else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001106 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001107#endif
1108 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001109 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001110 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001111 printf(_("type: %d\n"), lp->d_type);
1112 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1113 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1114 printf(_("flags:"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001115 if (lp->d_flags & BSD_D_REMOVABLE)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001116 printf(_(" removable"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001117 if (lp->d_flags & BSD_D_ECC)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001118 printf(_(" ecc"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001119 if (lp->d_flags & BSD_D_BADSECT)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001120 printf(_(" badsect"));
1121 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001122 /* On various machines the fields of *lp are short/int/long */
1123 /* In order to avoid problems, we cast them all to long. */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001124 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1125 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1126 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1127 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1128 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1129 printf(_("rpm: %d\n"), lp->d_rpm);
1130 printf(_("interleave: %d\n"), lp->d_interleave);
1131 printf(_("trackskew: %d\n"), lp->d_trackskew);
1132 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1133 printf(_("headswitch: %ld\t\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001134 (long) lp->d_headswitch);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001135 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001136 (long) lp->d_trkseek);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001137 printf(_("drivedata: "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001138 for (i = NDDATA - 1; i >= 0; i--)
1139 if (lp->d_drivedata[i])
1140 break;
1141 if (i < 0)
1142 i = 0;
1143 for (j = 0; j <= i; j++)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001144 printf("%ld ", (long) lp->d_drivedata[j]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001145 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001146 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1147 printf(_("# start end size fstype [fsize bsize cpg]\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001148 pp = lp->d_partitions;
1149 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1150 if (pp->p_size) {
1151 if (display_in_cyl_units && lp->d_secpercyl) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001152 printf(" %c: %8ld%c %8ld%c %8ld%c ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001153 'a' + i,
1154 (long) pp->p_offset / lp->d_secpercyl + 1,
1155 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1156 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
1157 / lp->d_secpercyl,
1158 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1159 (long) pp->p_size / lp->d_secpercyl,
1160 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
1161 } else {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001162 printf(" %c: %8ld %8ld %8ld ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001163 'a' + i,
1164 (long) pp->p_offset,
1165 (long) pp->p_offset + pp->p_size - 1,
1166 (long) pp->p_size);
1167 }
1168 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001169 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001170 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001171 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001172 switch (pp->p_fstype) {
1173 case BSD_FS_UNUSED:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001174 printf(" %5ld %5ld %5.5s ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001175 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1176 break;
1177
1178 case BSD_FS_BSDFFS:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001179 printf(" %5ld %5ld %5d ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001180 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
1181 pp->p_cpg);
1182 break;
1183
1184 default:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001185 printf("%22.22s", "");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001186 break;
1187 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001188 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001189 }
1190 }
1191}
1192
1193static void
1194xbsd_write_disklabel (void) {
1195#if defined (__alpha__)
1196 printf (_("Writing disklabel to %s.\n"), disk_device);
1197 xbsd_writelabel (NULL, &xbsd_dlabel);
1198#else
1199 printf (_("Writing disklabel to %s.\n"),
1200 partname(disk_device, xbsd_part_index+1, 0));
1201 xbsd_writelabel (xbsd_part, &xbsd_dlabel);
1202#endif
1203 reread_partition_table(0); /* no exit yet */
1204}
1205
1206static int
1207xbsd_create_disklabel (void) {
1208 char c;
1209
1210#if defined (__alpha__)
1211 fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
1212#else
1213 fprintf (stderr, _("%s contains no disklabel.\n"),
1214 partname(disk_device, xbsd_part_index+1, 0));
1215#endif
1216
1217 while (1) {
1218 c = read_char (_("Do you want to create a disklabel? (y/n) "));
1219 if (c == 'y' || c == 'Y') {
1220 if (xbsd_initlabel (
Eric Andersen040f4402003-07-30 08:40:37 +00001221#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
1222 defined (__s390__) || defined (__s390x__)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001223 NULL, &xbsd_dlabel, 0
1224#else
1225 xbsd_part, &xbsd_dlabel, xbsd_part_index
1226#endif
1227 ) == 1) {
1228 xbsd_print_disklabel (1);
1229 return 1;
1230 } else
1231 return 0;
1232 } else if (c == 'n')
1233 return 0;
1234 }
1235}
1236
1237static int
1238edit_int (int def, char *mesg)
1239{
1240 do {
1241 fputs (mesg, stdout);
1242 printf (" (%d): ", def);
1243 if (!read_line ())
1244 return def;
1245 }
1246 while (!isdigit (*line_ptr));
1247 return atoi (line_ptr);
1248}
1249
1250static void
1251xbsd_edit_disklabel (void)
1252{
1253 struct xbsd_disklabel *d;
1254
1255 d = &xbsd_dlabel;
1256
1257#if defined (__alpha__) || defined (__ia64__)
1258 d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,_("bytes/sector"));
1259 d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,_("sectors/track"));
1260 d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,_("tracks/cylinder"));
1261 d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,_("cylinders"));
1262#endif
1263
1264 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
1265 while (1)
1266 {
1267 d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
1268 _("sectors/cylinder"));
1269 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
1270 break;
1271
1272 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1273 }
1274 d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,_("rpm"));
1275 d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
1276 d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
1277 d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,_("cylinderskew"));
1278 d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,_("headswitch"));
1279 d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,_("track-to-track seek"));
1280
1281 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1282}
1283
1284static int
1285xbsd_get_bootstrap (char *path, void *ptr, int size)
1286{
1287 int fdb;
1288
1289 if ((fdb = open (path, O_RDONLY)) < 0)
1290 {
1291 perror (path);
1292 return 0;
1293 }
1294 if (read (fdb, ptr, size) < 0)
1295 {
1296 perror (path);
1297 close (fdb);
1298 return 0;
1299 }
1300 printf (" ... %s\n", path);
1301 close (fdb);
1302 return 1;
1303}
1304
1305static void
1306sync_disks (void)
1307{
1308 printf (_("\nSyncing disks.\n"));
1309 sync ();
1310 sleep (4);
1311}
1312
1313static void
1314xbsd_write_bootstrap (void)
1315{
1316 char *bootdir = BSD_LINUX_BOOTDIR;
1317 char path[MAXPATHLEN];
1318 char *dkbasename;
1319 struct xbsd_disklabel dl;
1320 char *d, *p, *e;
1321 int sector;
1322
1323 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1324 dkbasename = "sd";
1325 else
1326 dkbasename = "wd";
1327
1328 printf (_("Bootstrap: %sboot -> boot%s (%s): "),
1329 dkbasename, dkbasename, dkbasename);
1330 if (read_line ()) {
1331 line_ptr[strlen (line_ptr)-1] = '\0';
1332 dkbasename = line_ptr;
1333 }
1334 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1335 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1336 return;
1337
1338 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1339 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1340 bcopy (d, &dl, sizeof (struct xbsd_disklabel));
1341
1342 /* The disklabel will be overwritten by 0's from bootxx anyway */
1343 bzero (d, sizeof (struct xbsd_disklabel));
1344
1345 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1346 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1347 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1348 return;
1349
1350 e = d + sizeof (struct xbsd_disklabel);
1351 for (p=d; p < e; p++)
1352 if (*p) {
1353 fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
1354 exit ( EXIT_FAILURE );
1355 }
1356
1357 bcopy (&dl, d, sizeof (struct xbsd_disklabel));
1358
1359#if defined (__powerpc__) || defined (__hppa__)
1360 sector = 0;
1361#elif defined (__alpha__)
1362 sector = 0;
1363 alpha_bootblock_checksum (disklabelbuffer);
1364#else
1365 sector = get_start_sect(xbsd_part);
1366#endif
1367
Eric Andersen0a92f352004-03-30 09:21:54 +00001368 if (lseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001369 fdisk_fatal (unable_to_seek);
1370 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1371 fdisk_fatal (unable_to_write);
1372
1373#if defined (__alpha__)
1374 printf (_("Bootstrap installed on %s.\n"), disk_device);
1375#else
1376 printf (_("Bootstrap installed on %s.\n"),
1377 partname (disk_device, xbsd_part_index+1, 0));
1378#endif
1379
1380 sync_disks ();
1381}
1382
1383static void
1384xbsd_change_fstype (void)
1385{
1386 int i;
1387
1388 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1389 xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
1390}
1391
1392static int
1393xbsd_get_part_index (int max)
1394{
1395 char prompt[256];
1396 char l;
1397
1398 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1399 do
1400 l = tolower (read_char (prompt));
1401 while (l < 'a' || l > 'a' + max - 1);
1402 return l - 'a';
1403}
1404
1405static int
1406xbsd_check_new_partition (int *i) {
1407
1408 /* room for more? various BSD flavours have different maxima */
1409 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1410 int t;
1411
1412 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1413 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1414 break;
1415
1416 if (t == BSD_MAXPARTITIONS) {
1417 fprintf (stderr, _("The maximum number of partitions "
1418 "has been created\n"));
1419 return 0;
1420 }
1421 }
1422
1423 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1424
1425 if (*i >= xbsd_dlabel.d_npartitions)
1426 xbsd_dlabel.d_npartitions = (*i) + 1;
1427
1428 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1429 fprintf (stderr, _("This partition already exists.\n"));
1430 return 0;
1431 }
1432
1433 return 1;
1434}
1435
1436static void
1437xbsd_list_types (void) {
1438 list_types (xbsd_fstypes);
1439}
1440
1441static u_short
1442xbsd_dkcksum (struct xbsd_disklabel *lp) {
1443 u_short *start, *end;
1444 u_short sum = 0;
1445
1446 start = (u_short *) lp;
1447 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1448 while (start < end)
1449 sum ^= *start++;
1450 return sum;
1451}
1452
1453static int
1454xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) {
1455 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001456
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001457 get_geometry ();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001458 bzero (d, sizeof (struct xbsd_disklabel));
1459
1460 d -> d_magic = BSD_DISKMAGIC;
1461
1462 if (strncmp (disk_device, "/dev/sd", 7) == 0)
1463 d -> d_type = BSD_DTYPE_SCSI;
1464 else
1465 d -> d_type = BSD_DTYPE_ST506;
1466
1467#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
1468 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
1469#endif
1470
1471#if !defined (__alpha__)
1472 d -> d_flags = BSD_D_DOSPART;
1473#else
1474 d -> d_flags = 0;
1475#endif
1476 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001477 d -> d_nsectors = sectors; /* sectors/track */
1478 d -> d_ntracks = heads; /* tracks/cylinder (heads) */
1479 d -> d_ncylinders = cylinders;
1480 d -> d_secpercyl = sectors * heads;/* sectors/cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001481 if (d -> d_secpercyl == 0)
1482 d -> d_secpercyl = 1; /* avoid segfaults */
1483 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1484
1485 d -> d_rpm = 3600;
1486 d -> d_interleave = 1;
1487 d -> d_trackskew = 0;
1488 d -> d_cylskew = 0;
1489 d -> d_headswitch = 0;
1490 d -> d_trkseek = 0;
1491
1492 d -> d_magic2 = BSD_DISKMAGIC;
1493 d -> d_bbsize = BSD_BBSIZE;
1494 d -> d_sbsize = BSD_SBSIZE;
1495
1496#if !defined (__alpha__)
1497 d -> d_npartitions = 4;
1498 pp = &d -> d_partitions[2]; /* Partition C should be
1499 the NetBSD partition */
1500 pp -> p_offset = get_start_sect(p);
1501 pp -> p_size = get_nr_sects(p);
1502 pp -> p_fstype = BSD_FS_UNUSED;
1503 pp = &d -> d_partitions[3]; /* Partition D should be
1504 the whole disk */
1505 pp -> p_offset = 0;
1506 pp -> p_size = d -> d_secperunit;
1507 pp -> p_fstype = BSD_FS_UNUSED;
1508#elif defined (__alpha__)
1509 d -> d_npartitions = 3;
1510 pp = &d -> d_partitions[2]; /* Partition C should be
1511 the whole disk */
1512 pp -> p_offset = 0;
1513 pp -> p_size = d -> d_secperunit;
1514 pp -> p_fstype = BSD_FS_UNUSED;
1515#endif
1516
1517 return 1;
1518}
1519
1520/*
1521 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1522 * If it has the right magic, return 1.
1523 */
1524static int
1525xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1526{
1527 int t, sector;
1528
1529 /* p is used only to get the starting sector */
1530#if !defined (__alpha__)
1531 sector = (p ? get_start_sect(p) : 0);
1532#elif defined (__alpha__)
1533 sector = 0;
1534#endif
1535
Eric Andersen0a92f352004-03-30 09:21:54 +00001536 if (lseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001537 fdisk_fatal (unable_to_seek);
1538 if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
1539 fdisk_fatal (unable_to_read);
1540
1541 bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1542 d, sizeof (struct xbsd_disklabel));
1543
1544 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
1545 return 0;
1546
1547 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1548 d -> d_partitions[t].p_size = 0;
1549 d -> d_partitions[t].p_offset = 0;
1550 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
1551 }
1552
1553 if (d -> d_npartitions > BSD_MAXPARTITIONS)
1554 fprintf (stderr, _("Warning: too many partitions "
1555 "(%d, maximum is %d).\n"),
1556 d -> d_npartitions, BSD_MAXPARTITIONS);
1557 return 1;
1558}
1559
1560static int
1561xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1562{
Eric Andersen040f4402003-07-30 08:40:37 +00001563 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001564
1565#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1566 sector = get_start_sect(p) + BSD_LABELSECTOR;
1567#else
1568 sector = BSD_LABELSECTOR;
1569#endif
1570
1571 d -> d_checksum = 0;
1572 d -> d_checksum = xbsd_dkcksum (d);
1573
1574 /* This is necessary if we want to write the bootstrap later,
1575 otherwise we'd write the old disklabel with the bootstrap.
1576 */
1577 bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1578 sizeof (struct xbsd_disklabel));
1579
1580#if defined (__alpha__) && BSD_LABELSECTOR == 0
1581 alpha_bootblock_checksum (disklabelbuffer);
Eric Andersen0a92f352004-03-30 09:21:54 +00001582 if (lseek (fd, 0, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001583 fdisk_fatal (unable_to_seek);
1584 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1585 fdisk_fatal (unable_to_write);
1586#else
Eric Andersen0a92f352004-03-30 09:21:54 +00001587 if (lseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001588 SEEK_SET) == -1)
1589 fdisk_fatal (unable_to_seek);
1590 if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel)))
1591 fdisk_fatal (unable_to_write);
1592#endif
1593
1594 sync_disks ();
1595
1596 return 1;
1597}
1598
1599
1600#if !defined (__alpha__)
1601static int
1602xbsd_translate_fstype (int linux_type)
1603{
1604 switch (linux_type)
1605 {
1606 case 0x01: /* DOS 12-bit FAT */
1607 case 0x04: /* DOS 16-bit <32M */
1608 case 0x06: /* DOS 16-bit >=32M */
1609 case 0xe1: /* DOS access */
1610 case 0xe3: /* DOS R/O */
1611 case 0xf2: /* DOS secondary */
1612 return BSD_FS_MSDOS;
1613 case 0x07: /* OS/2 HPFS */
1614 return BSD_FS_HPFS;
1615 default:
1616 return BSD_FS_OTHER;
1617 }
1618}
1619
1620static void
1621xbsd_link_part (void)
1622{
1623 int k, i;
1624 struct partition *p;
1625
1626 k = get_partition (1, partitions);
1627
1628 if (!xbsd_check_new_partition (&i))
1629 return;
1630
1631 p = get_part_table(k);
1632
1633 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1634 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1635 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1636}
1637#endif
1638
1639#if defined (__alpha__)
1640
1641#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001642typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001643#endif
1644
1645static void
1646alpha_bootblock_checksum (char *boot)
1647{
Eric Andersendfcb5b02004-01-30 22:54:20 +00001648 uint64_t *dp, sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001649 int i;
1650
Eric Andersendfcb5b02004-01-30 22:54:20 +00001651 dp = (uint64_t *)boot;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001652 sum = 0;
1653 for (i = 0; i < 63; i++)
1654 sum += dp[i];
1655 dp[63] = sum;
1656}
1657#endif /* __alpha__ */
1658
1659#endif /* OSF_LABEL */
1660
1661#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1662static inline unsigned short
1663__swap16(unsigned short x) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001664 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001665}
1666
Eric Andersenacd244a2002-12-11 03:49:33 +00001667static inline uint32_t
1668__swap32(uint32_t x) {
Eric Andersen040f4402003-07-30 08:40:37 +00001669 return (((x & 0xFF) << 24) |
1670 ((x & 0xFF00) << 8) |
1671 ((x & 0xFF0000) >> 8) |
1672 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001673}
1674#endif
1675
1676#ifdef CONFIG_FEATURE_SGI_LABEL
1677/*
1678 *
1679 * fdisksgilabel.c
1680 *
1681 * Copyright (C) Andreas Neuper, Sep 1998.
1682 * This file may be modified and redistributed under
1683 * the terms of the GNU Public License.
1684 *
1685 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1686 * Internationalization
1687 */
1688
1689
1690static int sgi_other_endian;
1691static int debug;
1692static short sgi_volumes=1;
1693
1694/*
1695 * only dealing with free blocks here
1696 */
1697
Eric Andersen040f4402003-07-30 08:40:37 +00001698typedef struct { unsigned int first; unsigned int last; } freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001699static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1700
1701static void
Eric Andersen040f4402003-07-30 08:40:37 +00001702setfreelist(int i, unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001703 freelist[i].first = f;
1704 freelist[i].last = l;
1705}
1706
1707static void
Eric Andersen040f4402003-07-30 08:40:37 +00001708add2freelist(unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001709 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001710 for ( ; i < 17 ; i++)
1711 if (freelist[i].last == 0)
1712 break;
1713 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001714}
1715
1716static void
1717clearfreelist(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00001718 int i;
1719
1720 for (i = 0; i < 17 ; i++)
1721 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001722}
1723
Eric Andersen040f4402003-07-30 08:40:37 +00001724static unsigned int
1725isinfreelist(unsigned int b) {
1726 int i;
1727
1728 for (i = 0; i < 17 ; i++)
1729 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001730 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001731 return 0;
1732}
1733 /* return last vacant block of this stride (never 0). */
1734 /* the '>=' is not quite correct, but simplifies the code */
1735/*
1736 * end of free blocks section
1737 */
1738
1739static const struct systypes sgi_sys_types[] = {
1740/* SGI_VOLHDR */ {"\x00" "SGI volhdr" },
1741/* 0x01 */ {"\x01" "SGI trkrepl" },
1742/* 0x02 */ {"\x02" "SGI secrepl" },
1743/* SGI_SWAP */ {"\x03" "SGI raw" },
1744/* 0x04 */ {"\x04" "SGI bsd" },
1745/* 0x05 */ {"\x05" "SGI sysv" },
1746/* ENTIRE_DISK */ {"\x06" "SGI volume" },
1747/* SGI_EFS */ {"\x07" "SGI efs" },
1748/* 0x08 */ {"\x08" "SGI lvol" },
1749/* 0x09 */ {"\x09" "SGI rlvol" },
1750/* SGI_XFS */ {"\x0a" "SGI xfs" },
1751/* SGI_XFSLOG */ {"\x0b" "SGI xfslog" },
1752/* SGI_XLV */ {"\x0c" "SGI xlv" },
1753/* SGI_XVM */ {"\x0d" "SGI xvm" },
1754/* LINUX_SWAP */ {"\x82" "Linux swap" },
1755/* LINUX_NATIVE */ {"\x83" "Linux native" },
1756/* LINUX_LVM */ {"\x8d" "Linux LVM" },
1757/* LINUX_RAID */ {"\xfd" "Linux RAID" },
1758 { NULL }
1759};
1760
1761
1762static int
1763sgi_get_nsect(void) {
1764 return SGI_SSWAP16(sgilabel->devparam.nsect);
1765}
1766
1767static int
1768sgi_get_ntrks(void) {
1769 return SGI_SSWAP16(sgilabel->devparam.ntrks);
1770}
1771
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001772static void
1773sgi_nolabel(void) {
1774 sgilabel->magic = 0;
1775 sgi_label = 0;
1776 partitions = 4;
1777}
1778
1779static unsigned int
Eric Andersen040f4402003-07-30 08:40:37 +00001780two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001781 int i=0;
1782 unsigned int sum=0;
1783
Eric Andersen040f4402003-07-30 08:40:37 +00001784 size /= sizeof(unsigned int);
1785 for (i = 0; i < size; i++)
1786 sum -= SGI_SSWAP32(base[i]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001787 return sum;
1788}
1789
1790static int
1791check_sgi_label(void) {
1792 if (sizeof(sgilabel) > 512) {
1793 fprintf(stderr,
1794 _("According to MIPS Computer Systems, Inc the "
1795 "Label must not contain more than 512 bytes\n"));
1796 exit(1);
1797 }
1798
1799 if (sgilabel->magic != SGI_LABEL_MAGIC &&
1800 sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1801 sgi_label = 0;
1802 sgi_other_endian = 0;
1803 return 0;
1804 }
1805
1806 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1807 /*
1808 * test for correct checksum
1809 */
Eric Andersen040f4402003-07-30 08:40:37 +00001810 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1811 sizeof(*sgilabel))) {
1812 fprintf(stderr,
1813 _("Detected sgi disklabel with wrong checksum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001814 }
1815 update_units();
1816 sgi_label = 1;
1817 partitions= 16;
1818 sgi_volumes = 15;
1819 return 1;
1820}
1821
Eric Andersen040f4402003-07-30 08:40:37 +00001822static unsigned int
1823sgi_get_start_sector(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001824 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1825}
1826
Eric Andersen040f4402003-07-30 08:40:37 +00001827static unsigned int
1828sgi_get_num_sectors(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001829 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1830}
1831
1832static int
Eric Andersen040f4402003-07-30 08:40:37 +00001833sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001834{
1835 return SGI_SSWAP32(sgilabel->partitions[i].id);
1836}
1837
1838static int
1839sgi_get_bootpartition(void)
1840{
1841 return SGI_SSWAP16(sgilabel->boot_part);
1842}
1843
1844static int
1845sgi_get_swappartition(void)
1846{
1847 return SGI_SSWAP16(sgilabel->swap_part);
1848}
1849
1850static void
Eric Andersen040f4402003-07-30 08:40:37 +00001851sgi_list_table(int xtra) {
Eric Andersen99a75d12003-08-08 20:04:56 +00001852 int i, w, wd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001853 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001854
Eric Andersen040f4402003-07-30 08:40:37 +00001855 if(xtra) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001856 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1857 "%d cylinders, %d physical cylinders\n"
1858 "%d extra sects/cyl, interleave %d:1\n"
1859 "%s\n"
1860 "Units = %s of %d * 512 bytes\n\n"),
1861 disk_device, heads, sectors, cylinders,
1862 SGI_SSWAP16(sgiparam.pcylcount),
1863 SGI_SSWAP16(sgiparam.sparecyl),
1864 SGI_SSWAP16(sgiparam.ilfact),
1865 (char *)sgilabel,
1866 str_units(PLURAL), units_per_sector);
1867 } else {
1868 printf( _("\nDisk %s (SGI disk label): "
1869 "%d heads, %d sectors, %d cylinders\n"
1870 "Units = %s of %d * 512 bytes\n\n"),
1871 disk_device, heads, sectors, cylinders,
1872 str_units(PLURAL), units_per_sector );
1873 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001874
1875 w = strlen(disk_device);
1876 wd = strlen(_("Device"));
1877 if (w < wd)
1878 w = wd;
1879
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001880 printf(_("----- partitions -----\n"
1881 "Pt# %*s Info Start End Sectors Id System\n"),
Eric Andersen99a75d12003-08-08 20:04:56 +00001882 w + 2, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001883 for (i = 0 ; i < partitions; i++) {
1884 if( sgi_get_num_sectors(i) || debug ) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001885 uint32_t start = sgi_get_start_sector(i);
1886 uint32_t len = sgi_get_num_sectors(i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001887 kpi++; /* only count nonempty partitions */
1888 printf(
1889 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1890/* fdisk part number */ i+1,
Eric Andersen99a75d12003-08-08 20:04:56 +00001891/* device */ partname(disk_device, kpi, w+3),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001892/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1893/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1894/* start */ (long) scround(start),
1895/* end */ (long) scround(start+len)-1,
1896/* no odd flag on end */ (long) len,
1897/* type id */ sgi_get_sysid(i),
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001898/* type name */ partition_type(sgi_get_sysid(i)));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001899 }
1900 }
1901 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1902 "----- Directory Entries -----\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00001903 sgilabel->boot_file);
1904 for (i = 0 ; i < sgi_volumes; i++) {
1905 if (sgilabel->directory[i].vol_file_size) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001906 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1907 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001908 char*name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001909
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001910 printf(_("%2d: %-10s sector%5u size%8u\n"),
1911 i, name, (unsigned int) start, (unsigned int) len);
1912 }
1913 }
1914}
1915
1916static void
1917sgi_set_bootpartition( int i )
1918{
1919 sgilabel->boot_part = SGI_SSWAP16(((short)i));
1920}
1921
Eric Andersen040f4402003-07-30 08:40:37 +00001922static unsigned int
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001923sgi_get_lastblock(void) {
1924 return heads * sectors * cylinders;
1925}
1926
1927static void
1928sgi_set_swappartition( int i ) {
1929 sgilabel->swap_part = SGI_SSWAP16(((short)i));
1930}
1931
1932static int
Eric Andersen040f4402003-07-30 08:40:37 +00001933sgi_check_bootfile(const char* aFile) {
1934
1935 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1936 printf(_("\nInvalid Bootfile!\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001937 "\tThe bootfile must be an absolute non-zero pathname,\n"
Eric Andersen040f4402003-07-30 08:40:37 +00001938 "\te.g. \"/unix\" or \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001939 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001940 } else {
1941 if (strlen(aFile) > 16) {
1942 printf(_("\n\tName of Bootfile too long: "
1943 "16 bytes maximum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001944 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001945 } else {
1946 if (aFile[0] != '/') {
1947 printf(_("\n\tBootfile must have a "
1948 "fully qualified pathname.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001949 return 0;
1950 }
Eric Andersen040f4402003-07-30 08:40:37 +00001951 }
1952 }
1953 if (strncmp(aFile, sgilabel->boot_file, 16)) {
1954 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1955 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001956 /* filename is correct and did change */
1957 return 1;
1958 }
1959 return 0; /* filename did not change */
1960}
1961
1962static const char *
1963sgi_get_bootfile(void) {
1964 return sgilabel->boot_file;
1965}
1966
1967static void
Eric Andersen040f4402003-07-30 08:40:37 +00001968sgi_set_bootfile(const char* aFile) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001969 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001970
1971 if (sgi_check_bootfile(aFile)) {
1972 while (i < 16) {
1973 if ((aFile[i] != '\n') /* in principle caught again by next line */
1974 && (strlen(aFile) > i))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001975 sgilabel->boot_file[i] = aFile[i];
1976 else
1977 sgilabel->boot_file[i] = 0;
1978 i++;
1979 }
Eric Andersen040f4402003-07-30 08:40:37 +00001980 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001981 }
1982}
1983
1984static void
1985create_sgiinfo(void)
1986{
1987 /* I keep SGI's habit to write the sgilabel to the second block */
Eric Andersen040f4402003-07-30 08:40:37 +00001988 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1989 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1990 strncpy(sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001991}
1992
Eric Andersen040f4402003-07-30 08:40:37 +00001993static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001994
1995static void
Eric Andersen040f4402003-07-30 08:40:37 +00001996sgi_write_table(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001997 sgilabel->csum = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001998 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001999 (unsigned int*)sgilabel,
Eric Andersen040f4402003-07-30 08:40:37 +00002000 sizeof(*sgilabel)));
2001 assert(two_s_complement_32bit_sum(
2002 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
2003 if (lseek(fd, 0, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002004 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002005 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002006 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002007 if (! strncmp(sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002008 /*
Eric Andersen040f4402003-07-30 08:40:37 +00002009 * keep this habit of first writing the "sgilabel".
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002010 * I never tested whether it works without (AN 981002).
2011 */
Eric Andersen040f4402003-07-30 08:40:37 +00002012 sgiinfo *info = fill_sgiinfo();
2013 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
Eric Andersenbbbbcfe2004-03-30 09:33:18 +00002014 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002015 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002016 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002017 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002018 free(info);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002019 }
2020}
2021
2022static int
Eric Andersen040f4402003-07-30 08:40:37 +00002023compare_start(int *x, int *y) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002024 /*
2025 * sort according to start sectors
2026 * and prefers largest partition:
2027 * entry zero is entire disk entry
2028 */
Eric Andersen040f4402003-07-30 08:40:37 +00002029 unsigned int i = *x;
2030 unsigned int j = *y;
2031 unsigned int a = sgi_get_start_sector(i);
2032 unsigned int b = sgi_get_start_sector(j);
2033 unsigned int c = sgi_get_num_sectors(i);
2034 unsigned int d = sgi_get_num_sectors(j);
2035
2036 if (a == b)
2037 return (d > c) ? 1 : (d == c) ? 0 : -1;
2038 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002039}
2040
2041
2042static int
Eric Andersen040f4402003-07-30 08:40:37 +00002043verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002044{
2045 int Index[16]; /* list of valid partitions */
2046 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
Eric Andersen040f4402003-07-30 08:40:37 +00002047 int entire = 0, i = 0;
2048 unsigned int start = 0;
2049 long long gap = 0; /* count unused blocks */
2050 unsigned int lastblock = sgi_get_lastblock();
2051
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002052 clearfreelist();
Eric Andersen040f4402003-07-30 08:40:37 +00002053 for (i=0; i<16; i++) {
2054 if (sgi_get_num_sectors(i) != 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002055 Index[sortcount++]=i;
Eric Andersen040f4402003-07-30 08:40:37 +00002056 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2057 if (entire++ == 1) {
2058 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002059 printf(_("More than one entire disk entry present.\n"));
2060 }
2061 }
2062 }
2063 }
Eric Andersen040f4402003-07-30 08:40:37 +00002064 if (sortcount == 0) {
2065 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002066 printf(_("No partitions defined\n"));
Eric Andersen040f4402003-07-30 08:40:37 +00002067 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002068 }
Eric Andersen040f4402003-07-30 08:40:37 +00002069 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2070 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2071 if ((Index[0] != 10) && verbose)
2072 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2073 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2074 printf(_("The entire disk partition should start "
2075 "at block 0,\n"
2076 "not at diskblock %d.\n"),
2077 sgi_get_start_sector(Index[0]));
2078 if (debug) /* I do not understand how some disks fulfil it */
2079 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2080 printf(_("The entire disk partition is only %d diskblock large,\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002081 "but the disk is %d diskblocks long.\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00002082 sgi_get_num_sectors(Index[0]), lastblock);
2083 lastblock = sgi_get_num_sectors(Index[0]);
2084 } else {
2085 if (verbose)
2086 printf(_("One Partition (#11) should cover the entire disk.\n"));
2087 if (debug>2)
2088 printf("sysid=%d\tpartition=%d\n",
2089 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002090 }
Eric Andersen040f4402003-07-30 08:40:37 +00002091 for (i=1, start=0; i<sortcount; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002092 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
Eric Andersen040f4402003-07-30 08:40:37 +00002093
2094 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2095 if (debug) /* I do not understand how some disks fulfil it */
2096 if (verbose)
2097 printf(_("Partition %d does not start on cylinder boundary.\n"),
2098 Index[i]+1);
2099 }
2100 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2101 if (debug) /* I do not understand how some disks fulfil it */
2102 if (verbose)
2103 printf(_("Partition %d does not end on cylinder boundary.\n"),
2104 Index[i]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002105 }
2106 /* We cannot handle several "entire disk" entries. */
Eric Andersen040f4402003-07-30 08:40:37 +00002107 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2108 if (start > sgi_get_start_sector(Index[i])) {
2109 if (verbose)
2110 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002111 Index[i-1]+1, Index[i]+1,
Eric Andersen040f4402003-07-30 08:40:37 +00002112 start - sgi_get_start_sector(Index[i]));
2113 if (gap > 0) gap = -gap;
2114 if (gap == 0) gap = -1;
2115 }
2116 if (start < sgi_get_start_sector(Index[i])) {
2117 if (verbose)
2118 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2119 sgi_get_start_sector(Index[i]) - start,
2120 start, sgi_get_start_sector(Index[i])-1);
2121 gap += sgi_get_start_sector(Index[i]) - start;
2122 add2freelist(start, sgi_get_start_sector(Index[i]));
2123 }
2124 start = sgi_get_start_sector(Index[i])
2125 + sgi_get_num_sectors(Index[i]);
2126 if (debug > 1) {
2127 if (verbose)
2128 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002129 sgi_get_start_sector(Index[i]),
2130 sgi_get_num_sectors(Index[i]),
Eric Andersen040f4402003-07-30 08:40:37 +00002131 sgi_get_sysid(Index[i]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002132 }
2133 }
Eric Andersen040f4402003-07-30 08:40:37 +00002134 if (start < lastblock) {
2135 if (verbose)
2136 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2137 lastblock - start, start, lastblock-1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002138 gap += lastblock - start;
Eric Andersen040f4402003-07-30 08:40:37 +00002139 add2freelist(start, lastblock);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002140 }
2141 /*
2142 * Done with arithmetics
2143 * Go for details now
2144 */
Eric Andersen040f4402003-07-30 08:40:37 +00002145 if (verbose) {
2146 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2147 printf(_("\nThe boot partition does not exist.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002148 }
Eric Andersen040f4402003-07-30 08:40:37 +00002149 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2150 printf(_("\nThe swap partition does not exist.\n"));
2151 } else {
2152 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2153 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2154 printf(_("\nThe swap partition has no swap type.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002155 }
Eric Andersen040f4402003-07-30 08:40:37 +00002156 if (sgi_check_bootfile("/unix"))
2157 printf(_("\tYou have chosen an unusual boot file name.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002158 }
Eric Andersen040f4402003-07-30 08:40:37 +00002159 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002160}
2161
2162static int
2163sgi_gaps(void) {
2164 /*
2165 * returned value is:
2166 * = 0 : disk is properly filled to the rim
2167 * < 0 : there is an overlap
2168 * > 0 : there is still some vacant space
2169 */
2170 return verify_sgi(0);
2171}
2172
2173static void
2174sgi_change_sysid( int i, int sys )
2175{
2176 if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
2177 {
2178 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2179 return;
2180 }
2181 if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2182 && (sgi_get_start_sector(i)<1) )
2183 {
2184 read_chars(
2185 _("It is highly recommended that the partition at offset 0\n"
2186 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2187 "retrieve from its directory standalone tools like sash and fx.\n"
2188 "Only the \"SGI volume\" entire disk section may violate this.\n"
2189 "Type YES if you are sure about tagging this partition differently.\n"));
2190 if (strcmp (line_ptr, _("YES\n")))
2191 return;
2192 }
2193 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2194}
2195
2196/* returns partition index of first entry marked as entire disk */
2197static int
2198sgi_entire(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00002199 int i;
2200
2201 for(i=0; i<16; i++)
2202 if(sgi_get_sysid(i) == SGI_VOLUME)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002203 return i;
2204 return -1;
2205}
2206
2207static void
Eric Andersen040f4402003-07-30 08:40:37 +00002208sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
2209
2210 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2211 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2212 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002213 set_changed(i);
Eric Andersen040f4402003-07-30 08:40:37 +00002214 if (sgi_gaps() < 0) /* rebuild freelist */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002215 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2216}
2217
2218static void
2219sgi_set_entire(void) {
2220 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002221
2222 for(n=10; n < partitions; n++) {
2223 if(!sgi_get_num_sectors(n) ) {
2224 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002225 break;
2226 }
2227 }
2228}
2229
2230static void
2231sgi_set_volhdr(void)
2232{
2233 int n;
2234 for( n=8; n<partitions; n++ )
2235 {
2236 if(!sgi_get_num_sectors( n ) )
2237 {
2238 /*
2239 * 5 cylinders is an arbitrary value I like
2240 * IRIX 5.3 stored files in the volume header
2241 * (like sash, symmon, fx, ide) with ca. 3200
2242 * sectors.
2243 */
2244 if( heads * sectors * 5 < sgi_get_lastblock() )
2245 sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
2246 break;
2247 }
2248 }
2249}
2250
2251static void
2252sgi_delete_partition( int i )
2253{
2254 sgi_set_partition( i, 0, 0, 0 );
2255}
2256
2257static void
2258sgi_add_partition( int n, int sys )
2259{
2260 char mesg[256];
Eric Andersen040f4402003-07-30 08:40:37 +00002261 unsigned int first=0, last=0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002262
2263 if( n == 10 ) {
2264 sys = SGI_VOLUME;
2265 } else if ( n == 8 ) {
2266 sys = 0;
2267 }
Eric Andersen040f4402003-07-30 08:40:37 +00002268 if(sgi_get_num_sectors(n)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002269 printf(_("Partition %d is already defined. Delete "
2270 "it before re-adding it.\n"), n + 1);
2271 return;
2272 }
Eric Andersen040f4402003-07-30 08:40:37 +00002273 if( (sgi_entire() == -1) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002274 printf(_("Attempting to generate entire disk entry automatically.\n"));
2275 sgi_set_entire();
2276 sgi_set_volhdr();
2277 }
Eric Andersen040f4402003-07-30 08:40:37 +00002278 if( (sgi_gaps() == 0) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002279 printf(_("The entire disk is already covered with partitions.\n"));
2280 return;
2281 }
Eric Andersen040f4402003-07-30 08:40:37 +00002282 if(sgi_gaps() < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002283 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2284 return;
2285 }
2286 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2287 for(;;) {
2288 if(sys == SGI_VOLUME) {
2289 last = sgi_get_lastblock();
2290 first = read_int(0, 0, last-1, 0, mesg);
2291 if( first != 0 ) {
2292 printf(_("It is highly recommended that eleventh partition\n"
2293 "covers the entire disk and is of type `SGI volume'\n"));
2294 }
2295 } else {
2296 first = freelist[0].first;
2297 last = freelist[0].last;
2298 first = read_int(scround(first), scround(first), scround(last)-1,
2299 0, mesg);
2300 }
2301 if (display_in_cyl_units)
2302 first *= units_per_sector;
2303 else
2304 first = first; /* align to cylinder if you know how ... */
2305 if( !last )
2306 last = isinfreelist(first);
2307 if( last == 0 ) {
2308 printf(_("You will get a partition overlap on the disk. "
2309 "Fix it first!\n"));
2310 } else
2311 break;
2312 }
2313 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2314 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2315 scround(first), mesg)+1;
2316 if (display_in_cyl_units)
2317 last *= units_per_sector;
2318 else
2319 last = last; /* align to cylinder if You know how ... */
2320 if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
2321 printf(_("It is highly recommended that eleventh partition\n"
2322 "covers the entire disk and is of type `SGI volume'\n"));
2323 sgi_set_partition( n, first, last-first, sys );
2324}
2325
Eric Andersen040f4402003-07-30 08:40:37 +00002326#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002327static void
2328create_sgilabel(void)
2329{
2330 struct hd_geometry geometry;
Eric Andersen040f4402003-07-30 08:40:37 +00002331 struct {
2332 unsigned int start;
2333 unsigned int nsect;
2334 int sysid;
2335 } old[4];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002336 int i=0;
Eric Andersen040f4402003-07-30 08:40:37 +00002337 long longsectors; /* the number of sectors on the device */
2338 int res; /* the result from the ioctl */
2339 int sec_fac; /* the sector factor */
2340
2341 sec_fac = sector_size / 512; /* determine the sector factor */
2342
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002343 fprintf( stderr,
2344 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2345 "until you decide to write them. After that, of course, the previous\n"
2346 "content will be unrecoverably lost.\n\n"));
2347
2348 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
Eric Andersen040f4402003-07-30 08:40:37 +00002349 res = ioctl(fd, BLKGETSIZE, &longsectors);
2350 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002351 heads = geometry.heads;
2352 sectors = geometry.sectors;
Eric Andersen040f4402003-07-30 08:40:37 +00002353 if (res == 0) {
2354 /* the get device size ioctl was successful */
2355 cylinders = longsectors / (heads * sectors);
2356 cylinders /= sec_fac;
2357 } else {
2358 /* otherwise print error and use truncated version */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002359 cylinders = geometry.cylinders;
Eric Andersen040f4402003-07-30 08:40:37 +00002360 fprintf(stderr,
2361 _("Warning: BLKGETSIZE ioctl failed on %s. "
2362 "Using geometry cylinder value of %d.\n"
2363 "This value may be truncated for devices"
2364 " > 33.8 GB.\n"), disk_device, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002365 }
Eric Andersen040f4402003-07-30 08:40:37 +00002366 }
2367 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002368 old[i].sysid = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002369 if(valid_part_table_flag(MBRbuffer)) {
2370 if(get_part_table(i)->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002371 old[i].sysid = get_part_table(i)->sys_ind;
Eric Andersen040f4402003-07-30 08:40:37 +00002372 old[i].start = get_start_sect(get_part_table(i));
2373 old[i].nsect = get_nr_sects(get_part_table(i));
2374 printf(_("Trying to keep parameters of partition %d.\n"), i);
2375 if (debug)
2376 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2377 old[i].sysid, old[i].start, old[i].nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002378 }
2379 }
2380 }
Eric Andersen040f4402003-07-30 08:40:37 +00002381
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002382 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2383 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2384 sgilabel->boot_part = SGI_SSWAP16(0);
2385 sgilabel->swap_part = SGI_SSWAP16(1);
2386
2387 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2388 memset(sgilabel->boot_file, 0, 16);
2389 strcpy(sgilabel->boot_file, "/unix");
2390
2391 sgilabel->devparam.skew = (0);
2392 sgilabel->devparam.gap1 = (0);
2393 sgilabel->devparam.gap2 = (0);
2394 sgilabel->devparam.sparecyl = (0);
2395 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2396 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2397 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
2398 /* tracks/cylinder (heads) */
2399 sgilabel->devparam.cmd_tag_queue_depth = (0);
2400 sgilabel->devparam.unused0 = (0);
2401 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2402 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
2403 /* sectors/track */
2404 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2405 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2406 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
2407 IGNORE_ERRORS|RESEEK);
2408 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2409 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2410 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2411 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2412 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2413 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2414 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2415 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2416 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2417 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2418 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2419 sgi_label = 1;
2420 partitions = 16;
2421 sgi_volumes = 15;
2422 sgi_set_entire();
2423 sgi_set_volhdr();
Eric Andersen040f4402003-07-30 08:40:37 +00002424 for (i = 0; i < 4; i++) {
2425 if(old[i].sysid) {
2426 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002427 }
2428 }
2429}
2430
2431static void
2432sgi_set_xcyl(void)
2433{
2434 /* do nothing in the beginning */
2435}
Eric Andersen040f4402003-07-30 08:40:37 +00002436#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002437
2438/* _____________________________________________________________
2439 */
2440
Eric Andersen040f4402003-07-30 08:40:37 +00002441static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002442fill_sgiinfo(void)
2443{
Eric Andersen040f4402003-07-30 08:40:37 +00002444 sgiinfo *info = calloc(1, sizeof(sgiinfo));
2445
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002446 info->magic=SGI_SSWAP32(SGI_INFO_MAGIC);
2447 info->b1=SGI_SSWAP32(-1);
2448 info->b2=SGI_SSWAP16(-1);
2449 info->b3=SGI_SSWAP16(1);
2450 /* You may want to replace this string !!!!!!! */
2451 strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" );
2452 strcpy( info->serial, "0000" );
2453 info->check1816 = SGI_SSWAP16(18*256 +16 );
2454 strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
2455 return info;
2456}
2457#endif /* SGI_LABEL */
2458
2459
2460#ifdef CONFIG_FEATURE_SUN_LABEL
2461/*
2462 * fdisksunlabel.c
2463 *
2464 * I think this is mostly, or entirely, due to
2465 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2466 *
2467 * Merged with fdisk for other architectures, aeb, June 1998.
2468 *
2469 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2470 * Internationalization
2471 */
2472
2473
2474static int sun_other_endian;
2475static int scsi_disk;
2476static int floppy;
2477
2478#ifndef IDE0_MAJOR
2479#define IDE0_MAJOR 3
2480#endif
2481#ifndef IDE1_MAJOR
2482#define IDE1_MAJOR 22
2483#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002484
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002485static void guess_device_type(void) {
2486 struct stat bootstat;
2487
2488 if (fstat (fd, &bootstat) < 0) {
2489 scsi_disk = 0;
2490 floppy = 0;
2491 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002492 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2493 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002494 scsi_disk = 0;
2495 floppy = 0;
2496 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002497 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002498 scsi_disk = 0;
2499 floppy = 1;
2500 } else {
2501 scsi_disk = 1;
2502 floppy = 0;
2503 }
2504}
2505
2506static const struct systypes sun_sys_types[] = {
2507/* 0 */ {"\x00" "Empty" },
2508/* 1 */ {"\x01" "Boot" },
2509/* 2 */ {"\x02" "SunOS root" },
2510/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
2511/* 4 */ {"\x04" "SunOS usr" },
2512/* WHOLE_DISK */ {"\x05" "Whole disk" },
2513/* 6 */ {"\x06" "SunOS stand" },
2514/* 7 */ {"\x07" "SunOS var" },
2515/* 8 */ {"\x08" "SunOS home" },
2516/* LINUX_SWAP */ {"\x82" "Linux swap" },
2517/* LINUX_NATIVE */ {"\x83" "Linux native" },
2518/* 0x8e */ {"\x8e" "Linux LVM" },
2519/* New (2.2.x) raid partition with autodetect using persistent superblock */
2520/* 0xfd */ {"\xfd" "Linux raid autodetect" },
2521 { NULL }
2522};
2523
2524
2525static void
2526set_sun_partition(int i, uint start, uint stop, int sysid) {
2527 sunlabel->infos[i].id = sysid;
2528 sunlabel->partitions[i].start_cylinder =
2529 SUN_SSWAP32(start / (heads * sectors));
2530 sunlabel->partitions[i].num_sectors =
2531 SUN_SSWAP32(stop - start);
2532 set_changed(i);
2533}
2534
2535static void
2536sun_nolabel(void) {
2537 sun_label = 0;
2538 sunlabel->magic = 0;
2539 partitions = 4;
2540}
2541
2542static int
2543check_sun_label(void) {
2544 unsigned short *ush;
2545 int csum;
2546
2547 if (sunlabel->magic != SUN_LABEL_MAGIC &&
2548 sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2549 sun_label = 0;
2550 sun_other_endian = 0;
2551 return 0;
2552 }
2553 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2554 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2555 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2556 if (csum) {
2557 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2558 "Probably you'll have to set all the values,\n"
2559 "e.g. heads, sectors, cylinders and partitions\n"
2560 "or force a fresh label (s command in main menu)\n"));
2561 } else {
2562 heads = SUN_SSWAP16(sunlabel->ntrks);
2563 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2564 sectors = SUN_SSWAP16(sunlabel->nsect);
2565 }
2566 update_units();
2567 sun_label = 1;
2568 partitions = 8;
2569 return 1;
2570}
2571
2572static const struct sun_predefined_drives {
2573 const char *vendor;
2574 const char *model;
2575 unsigned short sparecyl;
2576 unsigned short ncyl;
2577 unsigned short nacyl;
2578 unsigned short pcylcount;
2579 unsigned short ntrks;
2580 unsigned short nsect;
2581 unsigned short rspeed;
2582} sun_drives[] = {
2583{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2584{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2585{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2586{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2587{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2588{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2589{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2590{"","SUN0104",1,974,2,1019,6,35,3662},
2591{"","SUN0207",4,1254,2,1272,9,36,3600},
2592{"","SUN0327",3,1545,2,1549,9,46,3600},
2593{"","SUN0340",0,1538,2,1544,6,72,4200},
2594{"","SUN0424",2,1151,2,2500,9,80,4400},
2595{"","SUN0535",0,1866,2,2500,7,80,5400},
2596{"","SUN0669",5,1614,2,1632,15,54,3600},
2597{"","SUN1.0G",5,1703,2,1931,15,80,3597},
2598{"","SUN1.05",0,2036,2,2038,14,72,5400},
2599{"","SUN1.3G",6,1965,2,3500,17,80,5400},
2600{"","SUN2.1G",0,2733,2,3500,19,80,5400},
2601{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2602};
2603
2604static const struct sun_predefined_drives *
2605sun_autoconfigure_scsi(void) {
2606 const struct sun_predefined_drives *p = NULL;
2607
2608#ifdef SCSI_IOCTL_GET_IDLUN
2609 unsigned int id[2];
2610 char buffer[2048];
2611 char buffer2[2048];
2612 FILE *pfd;
2613 char *vendor;
2614 char *model;
2615 char *q;
2616 int i;
2617
2618 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2619 sprintf(buffer,
2620 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2621#if 0
2622 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2623#else
2624 /* This is very wrong (works only if you have one HBA),
2625 but I haven't found a way how to get hostno
2626 from the current kernel */
2627 0,
2628#endif
2629 (id[0]>>16)&0xff,
2630 id[0]&0xff,
2631 (id[0]>>8)&0xff);
2632 pfd = fopen("/proc/scsi/scsi","r");
2633 if (pfd) {
2634 while (fgets(buffer2,2048,pfd)) {
2635 if (!strcmp(buffer, buffer2)) {
2636 if (fgets(buffer2,2048,pfd)) {
2637 q = strstr(buffer2,"Vendor: ");
2638 if (q) {
2639 q += 8;
2640 vendor = q;
2641 q = strstr(q," ");
2642 *q++ = 0; /* truncate vendor name */
2643 q = strstr(q,"Model: ");
2644 if (q) {
2645 *q = 0;
2646 q += 7;
2647 model = q;
2648 q = strstr(q," Rev: ");
2649 if (q) {
2650 *q = 0;
2651 for (i = 0; i < SIZE(sun_drives); i++) {
2652 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2653 continue;
2654 if (!strstr(model, sun_drives[i].model))
2655 continue;
2656 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2657 p = sun_drives + i;
2658 break;
2659 }
2660 }
2661 }
2662 }
2663 }
2664 break;
2665 }
2666 }
2667 fclose(pfd);
2668 }
2669 }
2670#endif
2671 return p;
2672}
2673
2674static void create_sunlabel(void)
2675{
2676 struct hd_geometry geometry;
2677 unsigned int ndiv;
2678 int i;
2679 unsigned char c;
2680 const struct sun_predefined_drives *p = NULL;
2681
2682 fprintf(stderr,
2683 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2684 "until you decide to write them. After that, of course, the previous\n"
2685 "content won't be recoverable.\n\n"));
2686#if BYTE_ORDER == LITTLE_ENDIAN
2687 sun_other_endian = 1;
2688#else
2689 sun_other_endian = 0;
2690#endif
2691 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2692 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2693 if (!floppy) {
2694 puts(_("Drive type\n"
2695 " ? auto configure\n"
2696 " 0 custom (with hardware detected defaults)"));
2697 for (i = 0; i < SIZE(sun_drives); i++) {
2698 printf(" %c %s%s%s\n",
2699 i + 'a', sun_drives[i].vendor,
2700 (*sun_drives[i].vendor) ? " " : "",
2701 sun_drives[i].model);
2702 }
2703 for (;;) {
2704 c = read_char(_("Select type (? for auto, 0 for custom): "));
2705 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2706 p = sun_drives + c - 'a';
2707 break;
2708 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2709 p = sun_drives + c - 'A';
2710 break;
2711 } else if (c == '0') {
2712 break;
2713 } else if (c == '?' && scsi_disk) {
2714 p = sun_autoconfigure_scsi();
2715 if (!p)
2716 printf(_("Autoconfigure failed.\n"));
2717 else
2718 break;
2719 }
2720 }
2721 }
2722 if (!p || floppy) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002723 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002724 heads = geometry.heads;
2725 sectors = geometry.sectors;
2726 cylinders = geometry.cylinders;
2727 } else {
2728 heads = 0;
2729 sectors = 0;
2730 cylinders = 0;
2731 }
2732 if (floppy) {
2733 sunlabel->nacyl = 0;
2734 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2735 sunlabel->rspeed = SUN_SSWAP16(300);
2736 sunlabel->ilfact = SUN_SSWAP16(1);
2737 sunlabel->sparecyl = 0;
2738 } else {
2739 heads = read_int(1,heads,1024,0,_("Heads"));
2740 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2741 if (cylinders)
2742 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2743 else
2744 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2745 sunlabel->nacyl =
2746 SUN_SSWAP16(read_int(0,2,65535,0,
2747 _("Alternate cylinders")));
2748 sunlabel->pcylcount =
2749 SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl),
2750 65535,0,_("Physical cylinders")));
2751 sunlabel->rspeed =
2752 SUN_SSWAP16(read_int(1,5400,100000,0,
2753 _("Rotation speed (rpm)")));
2754 sunlabel->ilfact =
2755 SUN_SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
2756 sunlabel->sparecyl =
2757 SUN_SSWAP16(read_int(0,0,sectors,0,
2758 _("Extra sectors per cylinder")));
2759 }
2760 } else {
2761 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2762 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2763 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2764 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2765 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2766 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2767 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2768 sunlabel->ilfact = SUN_SSWAP16(1);
2769 cylinders = p->ncyl;
2770 heads = p->ntrks;
2771 sectors = p->nsect;
2772 puts(_("You may change all the disk params from the x menu"));
2773 }
2774
2775 snprintf(sunlabel->info, sizeof(sunlabel->info),
2776 "%s%s%s cyl %d alt %d hd %d sec %d",
2777 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2778 p ? p->model
2779 : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2780 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2781
2782 sunlabel->ntrks = SUN_SSWAP16(heads);
2783 sunlabel->nsect = SUN_SSWAP16(sectors);
2784 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2785 if (floppy)
2786 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2787 else {
2788 if (cylinders * heads * sectors >= 150 * 2048) {
2789 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2790 } else
2791 ndiv = cylinders * 2 / 3;
2792 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2793 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2794 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2795 }
2796 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2797 {
2798 unsigned short *ush = (unsigned short *)sunlabel;
2799 unsigned short csum = 0;
2800 while(ush < (unsigned short *)(&sunlabel->csum))
2801 csum ^= *ush++;
2802 sunlabel->csum = csum;
2803 }
2804
2805 set_all_unchanged();
2806 set_changed(0);
2807 get_boot(create_empty_sun);
2808}
2809
2810static void
2811toggle_sunflags(int i, unsigned char mask) {
2812 if (sunlabel->infos[i].flags & mask)
2813 sunlabel->infos[i].flags &= ~mask;
2814 else sunlabel->infos[i].flags |= mask;
2815 set_changed(i);
2816}
2817
2818static void
2819fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) {
2820 int i, continuous = 1;
2821 *start = 0; *stop = cylinders * heads * sectors;
2822 for (i = 0; i < partitions; i++) {
2823 if (sunlabel->partitions[i].num_sectors
2824 && sunlabel->infos[i].id
2825 && sunlabel->infos[i].id != WHOLE_DISK) {
2826 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2827 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2828 if (continuous) {
2829 if (starts[i] == *start)
2830 *start += lens[i];
2831 else if (starts[i] + lens[i] >= *stop)
2832 *stop = starts[i];
2833 else
2834 continuous = 0;
2835 /* There will be probably more gaps
2836 than one, so lets check afterwards */
2837 }
2838 } else {
2839 starts[i] = 0;
2840 lens[i] = 0;
2841 }
2842 }
2843}
2844
2845static uint *verify_sun_starts;
2846
2847static int
2848verify_sun_cmp(int *a, int *b) {
2849 if (*a == -1) return 1;
2850 if (*b == -1) return -1;
2851 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2852 return -1;
2853}
2854
2855static void
2856verify_sun(void) {
2857 uint starts[8], lens[8], start, stop;
2858 int i,j,k,starto,endo;
2859 int array[8];
2860
2861 verify_sun_starts = starts;
2862 fetch_sun(starts,lens,&start,&stop);
2863 for (k = 0; k < 7; k++) {
2864 for (i = 0; i < 8; i++) {
2865 if (k && (lens[i] % (heads * sectors))) {
2866 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2867 }
2868 if (lens[i]) {
2869 for (j = 0; j < i; j++)
2870 if (lens[j]) {
2871 if (starts[j] == starts[i]+lens[i]) {
2872 starts[j] = starts[i]; lens[j] += lens[i];
2873 lens[i] = 0;
2874 } else if (starts[i] == starts[j]+lens[j]){
2875 lens[j] += lens[i];
2876 lens[i] = 0;
2877 } else if (!k) {
2878 if (starts[i] < starts[j]+lens[j] &&
2879 starts[j] < starts[i]+lens[i]) {
2880 starto = starts[i];
2881 if (starts[j] > starto)
2882 starto = starts[j];
2883 endo = starts[i]+lens[i];
2884 if (starts[j]+lens[j] < endo)
2885 endo = starts[j]+lens[j];
2886 printf(_("Partition %d overlaps with others in "
2887 "sectors %d-%d\n"), i+1, starto, endo);
2888 }
2889 }
2890 }
2891 }
2892 }
2893 }
2894 for (i = 0; i < 8; i++) {
2895 if (lens[i])
2896 array[i] = i;
2897 else
2898 array[i] = -1;
2899 }
2900 qsort(array,SIZE(array),sizeof(array[0]),
2901 (int (*)(const void *,const void *)) verify_sun_cmp);
2902 if (array[0] == -1) {
2903 printf(_("No partitions defined\n"));
2904 return;
2905 }
2906 stop = cylinders * heads * sectors;
2907 if (starts[array[0]])
2908 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2909 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2910 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2911 }
2912 start = starts[array[i]]+lens[array[i]];
2913 if (start < stop)
2914 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2915}
2916
2917static void
2918add_sun_partition(int n, int sys) {
2919 uint start, stop, stop2;
2920 uint starts[8], lens[8];
2921 int whole_disk = 0;
2922
2923 char mesg[256];
2924 int i, first, last;
2925
2926 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2927 printf(_("Partition %d is already defined. Delete "
2928 "it before re-adding it.\n"), n + 1);
2929 return;
2930 }
2931
2932 fetch_sun(starts,lens,&start,&stop);
2933 if (stop <= start) {
2934 if (n == 2)
2935 whole_disk = 1;
2936 else {
2937 printf(_("Other partitions already cover the whole disk.\nDelete "
2938 "some/shrink them before retry.\n"));
2939 return;
2940 }
2941 }
2942 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2943 for (;;) {
2944 if (whole_disk)
2945 first = read_int(0, 0, 0, 0, mesg);
2946 else
2947 first = read_int(scround(start), scround(stop)+1,
2948 scround(stop), 0, mesg);
2949 if (display_in_cyl_units)
2950 first *= units_per_sector;
2951 else
2952 /* Starting sector has to be properly aligned */
2953 first = (first + heads * sectors - 1) / (heads * sectors);
2954 if (n == 2 && first != 0)
2955 printf ("\
2956It is highly recommended that the third partition covers the whole disk\n\
2957and is of type `Whole disk'\n");
2958 /* ewt asks to add: "don't start a partition at cyl 0"
2959 However, edmundo@rano.demon.co.uk writes:
2960 "In addition to having a Sun partition table, to be able to
2961 boot from the disc, the first partition, /dev/sdX1, must
2962 start at cylinder 0. This means that /dev/sdX1 contains
2963 the partition table and the boot block, as these are the
2964 first two sectors of the disc. Therefore you must be
2965 careful what you use /dev/sdX1 for. In particular, you must
2966 not use a partition starting at cylinder 0 for Linux swap,
2967 as that would overwrite the partition table and the boot
2968 block. You may, however, use such a partition for a UFS
2969 or EXT2 file system, as these file systems leave the first
2970 1024 bytes undisturbed. */
2971 /* On the other hand, one should not use partitions
2972 starting at block 0 in an md, or the label will
2973 be trashed. */
2974 for (i = 0; i < partitions; i++)
2975 if (lens[i] && starts[i] <= first
2976 && starts[i] + lens[i] > first)
2977 break;
2978 if (i < partitions && !whole_disk) {
2979 if (n == 2 && !first) {
2980 whole_disk = 1;
2981 break;
2982 }
2983 printf(_("Sector %d is already allocated\n"), first);
2984 } else
2985 break;
2986 }
2987 stop = cylinders * heads * sectors;
2988 stop2 = stop;
2989 for (i = 0; i < partitions; i++) {
2990 if (starts[i] > first && starts[i] < stop)
2991 stop = starts[i];
2992 }
2993 snprintf(mesg, sizeof(mesg),
2994 _("Last %s or +size or +sizeM or +sizeK"),
2995 str_units(SINGULAR));
2996 if (whole_disk)
2997 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2998 0, mesg);
2999 else if (n == 2 && !first)
3000 last = read_int(scround(first), scround(stop2), scround(stop2),
3001 scround(first), mesg);
3002 else
3003 last = read_int(scround(first), scround(stop), scround(stop),
3004 scround(first), mesg);
3005 if (display_in_cyl_units)
3006 last *= units_per_sector;
3007 if (n == 2 && !first) {
3008 if (last >= stop2) {
3009 whole_disk = 1;
3010 last = stop2;
3011 } else if (last > stop) {
3012 printf (
3013 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
3014 "%d %s covers some other partition. Your entry has been changed\n"
3015 "to %d %s\n"),
3016 scround(last), str_units(SINGULAR),
3017 scround(stop), str_units(SINGULAR));
3018 last = stop;
3019 }
3020 } else if (!whole_disk && last > stop)
3021 last = stop;
3022
3023 if (whole_disk) sys = WHOLE_DISK;
3024 set_sun_partition(n, first, last, sys);
3025}
3026
3027static void
3028sun_delete_partition(int i) {
Eric Andersen040f4402003-07-30 08:40:37 +00003029 unsigned int nsec;
3030
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003031 if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
3032 !sunlabel->partitions[i].start_cylinder &&
Eric Andersen040f4402003-07-30 08:40:37 +00003033 (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003034 == heads * sectors * cylinders)
3035 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3036 "consider leaving this\n"
3037 "partition as Whole disk (5), starting at 0, with %u "
Eric Andersen040f4402003-07-30 08:40:37 +00003038 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003039 sunlabel->infos[i].id = 0;
3040 sunlabel->partitions[i].num_sectors = 0;
3041}
3042
3043static void
3044sun_change_sysid(int i, int sys) {
3045 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3046 read_chars(
3047 _("It is highly recommended that the partition at offset 0\n"
3048 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3049 "there may destroy your partition table and bootblock.\n"
3050 "Type YES if you're very sure you would like that partition\n"
3051 "tagged with 82 (Linux swap): "));
3052 if (strcmp (line_ptr, _("YES\n")))
3053 return;
3054 }
3055 switch (sys) {
3056 case SUNOS_SWAP:
3057 case LINUX_SWAP:
3058 /* swaps are not mountable by default */
3059 sunlabel->infos[i].flags |= 0x01;
3060 break;
3061 default:
3062 /* assume other types are mountable;
3063 user can change it anyway */
3064 sunlabel->infos[i].flags &= ~0x01;
3065 break;
3066 }
3067 sunlabel->infos[i].id = sys;
3068}
3069
3070static void
3071sun_list_table(int xtra) {
3072 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003073
3074 w = strlen(disk_device);
3075 if (xtra)
3076 printf(
3077 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3078 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3079 "%d extra sects/cyl, interleave %d:1\n"
3080 "%s\n"
3081 "Units = %s of %d * 512 bytes\n\n"),
3082 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3083 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3084 SUN_SSWAP16(sunlabel->pcylcount),
3085 SUN_SSWAP16(sunlabel->sparecyl),
3086 SUN_SSWAP16(sunlabel->ilfact),
3087 (char *)sunlabel,
3088 str_units(PLURAL), units_per_sector);
3089 else
3090 printf(
3091 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3092 "Units = %s of %d * 512 bytes\n\n"),
3093 disk_device, heads, sectors, cylinders,
3094 str_units(PLURAL), units_per_sector);
3095
3096 printf(_("%*s Flag Start End Blocks Id System\n"),
3097 w + 1, _("Device"));
3098 for (i = 0 ; i < partitions; i++) {
3099 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003100 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3101 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003102 printf(
3103 "%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3104/* device */ partname(disk_device, i+1, w),
3105/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
3106 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3107/* start */ (long) scround(start),
3108/* end */ (long) scround(start+len),
3109/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
3110/* type id */ sunlabel->infos[i].id,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003111/* type name */ partition_type(sunlabel->infos[i].id));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003112 }
3113 }
3114}
3115
Eric Andersen040f4402003-07-30 08:40:37 +00003116#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3117
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003118static void
3119sun_set_alt_cyl(void) {
3120 sunlabel->nacyl =
3121 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3122 _("Number of alternate cylinders")));
3123}
3124
3125static void
3126sun_set_ncyl(int cyl) {
3127 sunlabel->ncyl = SUN_SSWAP16(cyl);
3128}
3129
3130static void
3131sun_set_xcyl(void) {
3132 sunlabel->sparecyl =
3133 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3134 _("Extra sectors per cylinder")));
3135}
3136
3137static void
3138sun_set_ilfact(void) {
3139 sunlabel->ilfact =
3140 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3141 _("Interleave factor")));
3142}
3143
3144static void
3145sun_set_rspeed(void) {
3146 sunlabel->rspeed =
3147 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3148 _("Rotation speed (rpm)")));
3149}
3150
3151static void
3152sun_set_pcylcount(void) {
3153 sunlabel->pcylcount =
3154 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3155 _("Number of physical cylinders")));
3156}
Eric Andersen040f4402003-07-30 08:40:37 +00003157#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003158
3159static void
3160sun_write_table(void) {
3161 unsigned short *ush = (unsigned short *)sunlabel;
3162 unsigned short csum = 0;
3163
3164 while(ush < (unsigned short *)(&sunlabel->csum))
3165 csum ^= *ush++;
3166 sunlabel->csum = csum;
3167 if (lseek(fd, 0, SEEK_SET) < 0)
3168 fdisk_fatal(unable_to_seek);
3169 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3170 fdisk_fatal(unable_to_write);
3171}
3172#endif /* SUN_LABEL */
3173
3174/* DOS partition types */
3175
3176static const struct systypes i386_sys_types[] = {
3177 {"\x00" "Empty"},
3178 {"\x01" "FAT12"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003179 {"\x04" "FAT16 <32M"},
3180 {"\x05" "Extended"}, /* DOS 3.3+ extended partition */
3181 {"\x06" "FAT16"}, /* DOS 16-bit >=32M */
3182 {"\x07" "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003183 {"\x0a" "OS/2 Boot Manager"},/* OS/2 Boot Manager */
3184 {"\x0b" "Win95 FAT32"},
3185 {"\x0c" "Win95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
3186 {"\x0e" "Win95 FAT16 (LBA)"},
3187 {"\x0f" "Win95 Ext'd (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003188 {"\x11" "Hidden FAT12"},
3189 {"\x12" "Compaq diagnostics"},
3190 {"\x14" "Hidden FAT16 <32M"},
3191 {"\x16" "Hidden FAT16"},
3192 {"\x17" "Hidden HPFS/NTFS"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003193 {"\x1b" "Hidden Win95 FAT32"},
3194 {"\x1c" "Hidden Win95 FAT32 (LBA)"},
3195 {"\x1e" "Hidden Win95 FAT16 (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003196 {"\x3c" "PartitionMagic recovery"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003197 {"\x41" "PPC PReP Boot"},
3198 {"\x42" "SFS"},
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003199 {"\x63" "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3200 {"\x80" "Old Minix"}, /* Minix 1.4a and earlier */
3201 {"\x81" "Minix / old Linux"},/* Minix 1.4b and later */
3202 {"\x82" "Linux swap"}, /* also Solaris */
3203 {"\x83" "Linux"},
3204 {"\x84" "OS/2 hidden C: drive"},
3205 {"\x85" "Linux extended"},
3206 {"\x86" "NTFS volume set"},
3207 {"\x87" "NTFS volume set"},
3208 {"\x8e" "Linux LVM"},
3209 {"\x9f" "BSD/OS"}, /* BSDI */
3210 {"\xa0" "IBM Thinkpad hibernation"},
3211 {"\xa5" "FreeBSD"}, /* various BSD flavours */
3212 {"\xa6" "OpenBSD"},
3213 {"\xa8" "Darwin UFS"},
3214 {"\xa9" "NetBSD"},
3215 {"\xab" "Darwin boot"},
3216 {"\xb7" "BSDI fs"},
3217 {"\xb8" "BSDI swap"},
3218 {"\xbe" "Solaris boot"},
3219 {"\xeb" "BeOS fs"},
3220 {"\xee" "EFI GPT"}, /* Intel EFI GUID Partition Table */
3221 {"\xef" "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
3222 {"\xf0" "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
3223 {"\xf2" "DOS secondary"}, /* DOS 3.3+ secondary */
3224 {"\xfd" "Linux raid autodetect"},/* New (2.2.x) raid partition with
3225 autodetect using persistent
3226 superblock */
3227#ifdef CONFIG_WEIRD_PARTITION_TYPES
3228 {"\x02" "XENIX root"},
3229 {"\x03" "XENIX usr"},
3230 {"\x08" "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3231 {"\x09" "AIX bootable"}, /* AIX data or Coherent */
3232 {"\x10" "OPUS"},
3233 {"\x18" "AST SmartSleep"},
3234 {"\x24" "NEC DOS"},
3235 {"\x39" "Plan 9"},
3236 {"\x40" "Venix 80286"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003237 {"\x4d" "QNX4.x"},
3238 {"\x4e" "QNX4.x 2nd part"},
3239 {"\x4f" "QNX4.x 3rd part"},
3240 {"\x50" "OnTrack DM"},
3241 {"\x51" "OnTrack DM6 Aux1"}, /* (or Novell) */
3242 {"\x52" "CP/M"}, /* CP/M or Microport SysV/AT */
3243 {"\x53" "OnTrack DM6 Aux3"},
3244 {"\x54" "OnTrackDM6"},
3245 {"\x55" "EZ-Drive"},
3246 {"\x56" "Golden Bow"},
3247 {"\x5c" "Priam Edisk"},
3248 {"\x61" "SpeedStor"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003249 {"\x64" "Novell Netware 286"},
3250 {"\x65" "Novell Netware 386"},
3251 {"\x70" "DiskSecure Multi-Boot"},
3252 {"\x75" "PC/IX"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003253 {"\x93" "Amoeba"},
3254 {"\x94" "Amoeba BBT"}, /* (bad block table) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003255 {"\xa7" "NeXTSTEP"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003256 {"\xbb" "Boot Wizard hidden"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003257 {"\xc1" "DRDOS/sec (FAT-12)"},
3258 {"\xc4" "DRDOS/sec (FAT-16 < 32M)"},
3259 {"\xc6" "DRDOS/sec (FAT-16)"},
3260 {"\xc7" "Syrinx"},
3261 {"\xda" "Non-FS data"},
3262 {"\xdb" "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
3263 Concurrent DOS or CTOS */
3264 {"\xde" "Dell Utility"}, /* Dell PowerEdge Server utilities */
3265 {"\xdf" "BootIt"}, /* BootIt EMBRM */
3266 {"\xe1" "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
3267 extended partition */
3268 {"\xe3" "DOS R/O"}, /* DOS R/O or SpeedStor */
3269 {"\xe4" "SpeedStor"}, /* SpeedStor 16-bit FAT extended
3270 partition < 1024 cyl. */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003271 {"\xf1" "SpeedStor"},
3272 {"\xf4" "SpeedStor"}, /* SpeedStor large partition */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003273 {"\xfe" "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
3274 {"\xff" "BBT"}, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003275#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003276 { 0 }
3277};
3278
3279
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003280
3281/* A valid partition table sector ends in 0x55 0xaa */
3282static unsigned int
3283part_table_flag(const char *b) {
3284 return ((uint) b[510]) + (((uint) b[511]) << 8);
3285}
3286
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003287
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003288#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003289static void
3290write_part_table_flag(char *b) {
3291 b[510] = 0x55;
3292 b[511] = 0xaa;
3293}
3294
3295/* start_sect and nr_sects are stored little endian on all machines */
3296/* moreover, they are not aligned correctly */
3297static void
3298store4_little_endian(unsigned char *cp, unsigned int val) {
3299 cp[0] = (val & 0xff);
3300 cp[1] = ((val >> 8) & 0xff);
3301 cp[2] = ((val >> 16) & 0xff);
3302 cp[3] = ((val >> 24) & 0xff);
3303}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003304#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003305
3306static unsigned int
3307read4_little_endian(const unsigned char *cp) {
3308 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3309 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3310}
3311
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003312#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003313static void
3314set_start_sect(struct partition *p, unsigned int start_sect) {
3315 store4_little_endian(p->start4, start_sect);
3316}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003317#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003318
3319static unsigned int
3320get_start_sect(const struct partition *p) {
3321 return read4_little_endian(p->start4);
3322}
3323
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003324#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003325static void
3326set_nr_sects(struct partition *p, unsigned int nr_sects) {
3327 store4_little_endian(p->size4, nr_sects);
3328}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003329#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003330
3331static unsigned int
3332get_nr_sects(const struct partition *p) {
3333 return read4_little_endian(p->size4);
3334}
3335
3336/* normally O_RDWR, -l option gives O_RDONLY */
3337static int type_open = O_RDWR;
3338
3339
3340static int ext_index, /* the prime extended partition */
3341 listing, /* no aborts for fdisk -l */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003342 dos_compatible_flag = ~0;
3343#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3344static int dos_changed;
3345static int nowarn; /* no warnings for fdisk -l/-s */
3346#endif
3347
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003348
3349
3350static uint user_cylinders, user_heads, user_sectors;
3351static uint pt_heads, pt_sectors;
3352static uint kern_heads, kern_sectors;
3353
3354static uint extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003355
Eric Andersen040f4402003-07-30 08:40:37 +00003356static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003357
3358
3359static jmp_buf listingbuf;
3360
3361static void fdisk_fatal(enum failure why) {
3362 const char *message;
3363
3364 if (listing) {
3365 close(fd);
3366 longjmp(listingbuf, 1);
3367 }
3368
3369 switch (why) {
3370 case unable_to_open:
3371 message = "Unable to open %s\n";
3372 break;
3373 case unable_to_read:
3374 message = "Unable to read %s\n";
3375 break;
3376 case unable_to_seek:
3377 message = "Unable to seek on %s\n";
3378 break;
3379 case unable_to_write:
3380 message = "Unable to write %s\n";
3381 break;
3382 case ioctl_error:
3383 message = "BLKGETSIZE ioctl failed on %s\n";
3384 break;
3385 default:
3386 message = "Fatal error\n";
3387 }
3388
3389 fputc('\n', stderr);
3390 fprintf(stderr, message, disk_device);
3391 exit(1);
3392}
3393
3394static void
3395seek_sector(uint secno) {
Eric Andersen0a92f352004-03-30 09:21:54 +00003396 off_t offset = secno * sector_size;
3397 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003398 fdisk_fatal(unable_to_seek);
3399}
3400
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003401#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003402static void
3403write_sector(uint secno, char *buf) {
3404 seek_sector(secno);
3405 if (write(fd, buf, sector_size) != sector_size)
3406 fdisk_fatal(unable_to_write);
3407}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003408#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003409
3410/* Allocate a buffer and read a partition table sector */
3411static void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003412read_pte(struct pte *pe, uint offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003413
3414 pe->offset = offset;
3415 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003416 seek_sector(offset);
3417 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3418 fdisk_fatal(unable_to_read);
3419#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003420 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003421#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003422 pe->part_table = pe->ext_pointer = NULL;
3423}
3424
3425static unsigned int
3426get_partition_start(const struct pte *pe) {
3427 return pe->offset + get_start_sect(pe->part_table);
3428}
3429
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003430#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003431/*
3432 * Avoid warning about DOS partitions when no DOS partition was changed.
3433 * Here a heuristic "is probably dos partition".
3434 * We might also do the opposite and warn in all cases except
3435 * for "is probably nondos partition".
3436 */
3437static int
3438is_dos_partition(int t) {
3439 return (t == 1 || t == 4 || t == 6 ||
3440 t == 0x0b || t == 0x0c || t == 0x0e ||
3441 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3442 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3443 t == 0xc1 || t == 0xc4 || t == 0xc6);
3444}
3445
3446static void
3447menu(void) {
3448#ifdef CONFIG_FEATURE_SUN_LABEL
3449 if (sun_label) {
3450 puts(_("Command action"));
3451 puts(_("\ta\ttoggle a read only flag")); /* sun */
3452 puts(_("\tb\tedit bsd disklabel"));
3453 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3454 puts(_("\td\tdelete a partition"));
3455 puts(_("\tl\tlist known partition types"));
3456 puts(_("\tm\tprint this menu"));
3457 puts(_("\tn\tadd a new partition"));
3458 puts(_("\to\tcreate a new empty DOS partition table"));
3459 puts(_("\tp\tprint the partition table"));
3460 puts(_("\tq\tquit without saving changes"));
3461 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3462 puts(_("\tt\tchange a partition's system id"));
3463 puts(_("\tu\tchange display/entry units"));
3464 puts(_("\tv\tverify the partition table"));
3465 puts(_("\tw\twrite table to disk and exit"));
3466#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3467 puts(_("\tx\textra functionality (experts only)"));
3468#endif
3469 } else
3470#endif
3471#ifdef CONFIG_FEATURE_SGI_LABEL
3472 if (sgi_label) {
3473 puts(_("Command action"));
3474 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3475 puts(_("\tb\tedit bootfile entry")); /* sgi */
3476 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3477 puts(_("\td\tdelete a partition"));
3478 puts(_("\tl\tlist known partition types"));
3479 puts(_("\tm\tprint this menu"));
3480 puts(_("\tn\tadd a new partition"));
3481 puts(_("\to\tcreate a new empty DOS partition table"));
3482 puts(_("\tp\tprint the partition table"));
3483 puts(_("\tq\tquit without saving changes"));
3484 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3485 puts(_("\tt\tchange a partition's system id"));
3486 puts(_("\tu\tchange display/entry units"));
3487 puts(_("\tv\tverify the partition table"));
3488 puts(_("\tw\twrite table to disk and exit"));
3489 } else
3490#endif
3491#ifdef CONFIG_FEATURE_AIX_LABEL
3492 if (aix_label) {
3493 puts(_("Command action"));
3494 puts(_("\tm\tprint this menu"));
3495 puts(_("\to\tcreate a new empty DOS partition table"));
3496 puts(_("\tq\tquit without saving changes"));
3497 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3498 } else
3499#endif
3500 {
3501 puts(_("Command action"));
3502 puts(_("\ta\ttoggle a bootable flag"));
3503 puts(_("\tb\tedit bsd disklabel"));
3504 puts(_("\tc\ttoggle the dos compatibility flag"));
3505 puts(_("\td\tdelete a partition"));
3506 puts(_("\tl\tlist known partition types"));
3507 puts(_("\tm\tprint this menu"));
3508 puts(_("\tn\tadd a new partition"));
3509 puts(_("\to\tcreate a new empty DOS partition table"));
3510 puts(_("\tp\tprint the partition table"));
3511 puts(_("\tq\tquit without saving changes"));
3512 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3513 puts(_("\tt\tchange a partition's system id"));
3514 puts(_("\tu\tchange display/entry units"));
3515 puts(_("\tv\tverify the partition table"));
3516 puts(_("\tw\twrite table to disk and exit"));
3517#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3518 puts(_("\tx\textra functionality (experts only)"));
3519#endif
3520 }
3521}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003522#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3523
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003524
3525#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3526static void
3527xmenu(void) {
3528#ifdef CONFIG_FEATURE_SUN_LABEL
3529 if (sun_label) {
3530 puts(_("Command action"));
3531 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3532 puts(_("\tc\tchange number of cylinders"));
3533 puts(_("\td\tprint the raw data in the partition table"));
3534 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3535 puts(_("\th\tchange number of heads"));
3536 puts(_("\ti\tchange interleave factor")); /*sun*/
3537 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3538 puts(_("\tm\tprint this menu"));
3539 puts(_("\tp\tprint the partition table"));
3540 puts(_("\tq\tquit without saving changes"));
3541 puts(_("\tr\treturn to main menu"));
3542 puts(_("\ts\tchange number of sectors/track"));
3543 puts(_("\tv\tverify the partition table"));
3544 puts(_("\tw\twrite table to disk and exit"));
3545 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
3546 } else
3547#endif
3548#ifdef CONFIG_FEATURE_SGI_LABEL
3549 if (sgi_label) {
3550 puts(_("Command action"));
3551 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3552 puts(_("\tc\tchange number of cylinders"));
3553 puts(_("\td\tprint the raw data in the partition table"));
3554 puts(_("\te\tlist extended partitions")); /* !sun */
3555 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3556 puts(_("\th\tchange number of heads"));
3557 puts(_("\tm\tprint this menu"));
3558 puts(_("\tp\tprint the partition table"));
3559 puts(_("\tq\tquit without saving changes"));
3560 puts(_("\tr\treturn to main menu"));
3561 puts(_("\ts\tchange number of sectors/track"));
3562 puts(_("\tv\tverify the partition table"));
3563 puts(_("\tw\twrite table to disk and exit"));
3564 } else
3565#endif
3566#ifdef CONFIG_FEATURE_AIX_LABEL
3567 if (aix_label) {
3568 puts(_("Command action"));
3569 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3570 puts(_("\tc\tchange number of cylinders"));
3571 puts(_("\td\tprint the raw data in the partition table"));
3572 puts(_("\te\tlist extended partitions")); /* !sun */
3573 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3574 puts(_("\th\tchange number of heads"));
3575 puts(_("\tm\tprint this menu"));
3576 puts(_("\tp\tprint the partition table"));
3577 puts(_("\tq\tquit without saving changes"));
3578 puts(_("\tr\treturn to main menu"));
3579 puts(_("\ts\tchange number of sectors/track"));
3580 puts(_("\tv\tverify the partition table"));
3581 puts(_("\tw\twrite table to disk and exit"));
3582 } else
3583#endif
3584 {
3585 puts(_("Command action"));
3586 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3587 puts(_("\tc\tchange number of cylinders"));
3588 puts(_("\td\tprint the raw data in the partition table"));
3589 puts(_("\te\tlist extended partitions")); /* !sun */
3590 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
3591#ifdef CONFIG_FEATURE_SGI_LABEL
3592 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3593#endif
3594 puts(_("\th\tchange number of heads"));
3595 puts(_("\tm\tprint this menu"));
3596 puts(_("\tp\tprint the partition table"));
3597 puts(_("\tq\tquit without saving changes"));
3598 puts(_("\tr\treturn to main menu"));
3599 puts(_("\ts\tchange number of sectors/track"));
3600 puts(_("\tv\tverify the partition table"));
3601 puts(_("\tw\twrite table to disk and exit"));
3602 }
3603}
3604#endif /* ADVANCED mode */
3605
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003606#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003607static const struct systypes *
3608get_sys_types(void) {
3609 return (
3610#ifdef CONFIG_FEATURE_SUN_LABEL
3611 sun_label ? sun_sys_types :
3612#endif
3613#ifdef CONFIG_FEATURE_SGI_LABEL
3614 sgi_label ? sgi_sys_types :
3615#endif
3616 i386_sys_types);
3617}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003618#else
3619#define get_sys_types() i386_sys_types
3620#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003621
3622static const char *partition_type(unsigned char type)
3623{
3624 int i;
3625 const struct systypes *types = get_sys_types();
3626
3627 for (i=0; types[i].name; i++)
3628 if (types[i].name[0] == type)
3629 return types[i].name + 1;
3630
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003631 return _("Unknown");
3632}
3633
3634
3635#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3636static int
3637get_sysid(int i) {
3638 return (
3639#ifdef CONFIG_FEATURE_SUN_LABEL
3640 sun_label ? sunlabel->infos[i].id :
3641#endif
3642#ifdef CONFIG_FEATURE_SGI_LABEL
3643 sgi_label ? sgi_get_sysid(i) :
3644#endif
3645 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003646}
3647
3648void list_types(const struct systypes *sys)
3649{
3650 uint last[4], done = 0, next = 0, size;
3651 int i;
3652
3653 for (i = 0; sys[i].name; i++);
3654 size = i;
3655
3656 for (i = 3; i >= 0; i--)
3657 last[3 - i] = done += (size + i - done) / (i + 1);
3658 i = done = 0;
3659
3660 do {
3661 printf("%c%2x %-15.15s", i ? ' ' : '\n',
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003662 sys[next].name[0], partition_type(sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003663 next = last[i++] + done;
3664 if (i > 3 || next >= last[i]) {
3665 i = 0;
3666 next = ++done;
3667 }
3668 } while (done < last[0]);
3669 putchar('\n');
3670}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003671#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003672
3673static int
3674is_cleared_partition(const struct partition *p) {
3675 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3676 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3677 get_start_sect(p) || get_nr_sects(p));
3678}
3679
3680static void
3681clear_partition(struct partition *p) {
3682 if (!p)
3683 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003684 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003685}
3686
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003687#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003688static void
3689set_partition(int i, int doext, uint start, uint stop, int sysid) {
3690 struct partition *p;
3691 uint offset;
3692
3693 if (doext) {
3694 p = ptes[i].ext_pointer;
3695 offset = extended_offset;
3696 } else {
3697 p = ptes[i].part_table;
3698 offset = ptes[i].offset;
3699 }
3700 p->boot_ind = 0;
3701 p->sys_ind = sysid;
3702 set_start_sect(p, start - offset);
3703 set_nr_sects(p, stop - start + 1);
3704 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3705 start = heads*sectors*1024 - 1;
3706 set_hsc(p->head, p->sector, p->cyl, start);
3707 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3708 stop = heads*sectors*1024 - 1;
3709 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3710 ptes[i].changed = 1;
3711}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003712#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003713
3714static int
3715test_c(const char **m, const char *mesg) {
3716 int val = 0;
3717 if (!*m)
3718 fprintf(stderr, _("You must set"));
3719 else {
3720 fprintf(stderr, " %s", *m);
3721 val = 1;
3722 }
3723 *m = mesg;
3724 return val;
3725}
3726
3727static int
3728warn_geometry(void) {
3729 const char *m = NULL;
3730 int prev = 0;
3731
3732 if (!heads)
3733 prev = test_c(&m, _("heads"));
3734 if (!sectors)
3735 prev = test_c(&m, _("sectors"));
3736 if (!cylinders)
3737 prev = test_c(&m, _("cylinders"));
3738 if (!m)
3739 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003740
3741 fprintf(stderr, "%s%s.\n"
3742#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3743 "You can do this from the extra functions menu.\n"
3744#endif
3745 , prev ? _(" and ") : " ", m);
3746
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003747 return 1;
3748}
3749
3750static void update_units(void)
3751{
3752 int cyl_units = heads * sectors;
3753
3754 if (display_in_cyl_units && cyl_units)
3755 units_per_sector = cyl_units;
3756 else
3757 units_per_sector = 1; /* in sectors */
3758}
3759
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003760#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003761static void
3762warn_cylinders(void) {
3763 if (dos_label && cylinders > 1024 && !nowarn)
3764 fprintf(stderr, _("\n"
3765"The number of cylinders for this disk is set to %d.\n"
3766"There is nothing wrong with that, but this is larger than 1024,\n"
3767"and could in certain setups cause problems with:\n"
3768"1) software that runs at boot time (e.g., old versions of LILO)\n"
3769"2) booting and partitioning software from other OSs\n"
3770" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3771 cylinders);
3772}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003773#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003774
3775static void
3776read_extended(int ext) {
3777 int i;
3778 struct pte *pex;
3779 struct partition *p, *q;
3780
3781 ext_index = ext;
3782 pex = &ptes[ext];
3783 pex->ext_pointer = pex->part_table;
3784
3785 p = pex->part_table;
3786 if (!get_start_sect(p)) {
3787 fprintf(stderr,
3788 _("Bad offset in primary extended partition\n"));
3789 return;
3790 }
3791
3792 while (IS_EXTENDED (p->sys_ind)) {
3793 struct pte *pe = &ptes[partitions];
3794
3795 if (partitions >= MAXIMUM_PARTS) {
3796 /* This is not a Linux restriction, but
3797 this program uses arrays of size MAXIMUM_PARTS.
3798 Do not try to `improve' this test. */
3799 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003800#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003801 fprintf(stderr,
3802 _("Warning: deleting partitions after %d\n"),
3803 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003804 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003805#endif
3806 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003807 return;
3808 }
3809
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003810 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003811
3812 if (!extended_offset)
3813 extended_offset = get_start_sect(p);
3814
3815 q = p = pt_offset(pe->sectorbuffer, 0);
3816 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3817 if (IS_EXTENDED (p->sys_ind)) {
3818 if (pe->ext_pointer)
3819 fprintf(stderr,
3820 _("Warning: extra link "
3821 "pointer in partition table"
3822 " %d\n"), partitions + 1);
3823 else
3824 pe->ext_pointer = p;
3825 } else if (p->sys_ind) {
3826 if (pe->part_table)
3827 fprintf(stderr,
3828 _("Warning: ignoring extra "
3829 "data in partition table"
3830 " %d\n"), partitions + 1);
3831 else
3832 pe->part_table = p;
3833 }
3834 }
3835
3836 /* very strange code here... */
3837 if (!pe->part_table) {
3838 if (q != pe->ext_pointer)
3839 pe->part_table = q;
3840 else
3841 pe->part_table = q + 1;
3842 }
3843 if (!pe->ext_pointer) {
3844 if (q != pe->part_table)
3845 pe->ext_pointer = q;
3846 else
3847 pe->ext_pointer = q + 1;
3848 }
3849
3850 p = pe->ext_pointer;
3851 partitions++;
3852 }
3853
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003854#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003855 /* remove empty links */
3856 remove:
3857 for (i = 4; i < partitions; i++) {
3858 struct pte *pe = &ptes[i];
3859
3860 if (!get_nr_sects(pe->part_table) &&
3861 (partitions > 5 || ptes[4].part_table->sys_ind)) {
3862 printf("omitting empty partition (%d)\n", i+1);
3863 delete_partition(i);
3864 goto remove; /* numbering changed */
3865 }
3866 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003867#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003868}
3869
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003870#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003871static void
3872create_doslabel(void) {
3873 int i;
3874
3875 fprintf(stderr,
3876 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3877 "until you decide to write them. After that, of course, the previous\n"
3878 "content won't be recoverable.\n\n"));
3879#ifdef CONFIG_FEATURE_SUN_LABEL
3880 sun_nolabel(); /* otherwise always recognised as sun */
3881#endif
3882#ifdef CONFIG_FEATURE_SGI_LABEL
3883 sgi_nolabel(); /* otherwise always recognised as sgi */
3884#endif
3885#ifdef CONFIG_FEATURE_AIX_LABEL
3886 aix_label = 0;
3887#endif
3888#ifdef CONFIG_FEATURE_OSF_LABEL
3889 osf_label = 0;
3890 possibly_osf_label = 0;
3891#endif
3892 partitions = 4;
3893
3894 for (i = 510-64; i < 510; i++)
3895 MBRbuffer[i] = 0;
3896 write_part_table_flag(MBRbuffer);
3897 extended_offset = 0;
3898 set_all_unchanged();
3899 set_changed(0);
3900 get_boot(create_empty_dos);
3901}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003902#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003903
3904static void
3905get_sectorsize(void) {
3906 if (!user_set_sector_size &&
3907 get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
3908 int arg;
3909 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3910 sector_size = arg;
3911 if (sector_size != DEFAULT_SECTOR_SIZE)
3912 printf(_("Note: sector size is %d (not %d)\n"),
3913 sector_size, DEFAULT_SECTOR_SIZE);
3914 }
3915}
3916
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003917static inline void
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003918get_kernel_geometry(void) {
3919 struct hd_geometry geometry;
3920
3921 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3922 kern_heads = geometry.heads;
3923 kern_sectors = geometry.sectors;
3924 /* never use geometry.cylinders - it is truncated */
3925 }
3926}
3927
3928static void
3929get_partition_table_geometry(void) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003930 const unsigned char *bufp = MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003931 struct partition *p;
3932 int i, h, s, hh, ss;
3933 int first = 1;
3934 int bad = 0;
3935
3936 if (!(valid_part_table_flag(bufp)))
3937 return;
3938
3939 hh = ss = 0;
3940 for (i=0; i<4; i++) {
3941 p = pt_offset(bufp, i);
3942 if (p->sys_ind != 0) {
3943 h = p->end_head + 1;
3944 s = (p->end_sector & 077);
3945 if (first) {
3946 hh = h;
3947 ss = s;
3948 first = 0;
3949 } else if (hh != h || ss != s)
3950 bad = 1;
3951 }
3952 }
3953
3954 if (!first && !bad) {
3955 pt_heads = hh;
3956 pt_sectors = ss;
3957 }
3958}
3959
3960void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003961get_geometry(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003962 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003963 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003964
3965 get_sectorsize();
3966 sec_fac = sector_size / 512;
3967#ifdef CONFIG_FEATURE_SUN_LABEL
3968 guess_device_type();
3969#endif
3970 heads = cylinders = sectors = 0;
3971 kern_heads = kern_sectors = 0;
3972 pt_heads = pt_sectors = 0;
3973
3974 get_kernel_geometry();
3975 get_partition_table_geometry();
3976
3977 heads = user_heads ? user_heads :
3978 pt_heads ? pt_heads :
3979 kern_heads ? kern_heads : 255;
3980 sectors = user_sectors ? user_sectors :
3981 pt_sectors ? pt_sectors :
3982 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003983 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3984 /* got bytes */
3985 } else {
3986 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003987
3988 if (ioctl(fd, BLKGETSIZE, &longsectors))
3989 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00003990 bytes = ((unsigned long long) longsectors) << 9;
3991 }
3992
3993 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003994
3995 sector_offset = 1;
3996 if (dos_compatible_flag)
3997 sector_offset = sectors;
3998
Eric Andersen040f4402003-07-30 08:40:37 +00003999 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004000 if (!cylinders)
4001 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004002}
4003
4004/*
4005 * Read MBR. Returns:
4006 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4007 * 0: found or created label
4008 * 1: I/O error
4009 */
4010int
4011get_boot(enum action what) {
4012 int i;
4013
4014 partitions = 4;
4015
4016 for (i = 0; i < 4; i++) {
4017 struct pte *pe = &ptes[i];
4018
4019 pe->part_table = pt_offset(MBRbuffer, i);
4020 pe->ext_pointer = NULL;
4021 pe->offset = 0;
4022 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004023#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004024 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004025#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004026 }
4027
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004028#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004029 if (what == create_empty_sun && check_sun_label())
4030 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004031#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004032
4033 memset(MBRbuffer, 0, 512);
4034
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004035#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004036 if (what == create_empty_dos)
4037 goto got_dos_table; /* skip reading disk */
4038
4039 if ((fd = open(disk_device, type_open)) < 0) {
4040 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4041 if (what == try_only)
4042 return 1;
4043 fdisk_fatal(unable_to_open);
4044 } else
4045 printf(_("You will not be able to write "
4046 "the partition table.\n"));
4047 }
4048
4049 if (512 != read(fd, MBRbuffer, 512)) {
4050 if (what == try_only)
4051 return 1;
4052 fdisk_fatal(unable_to_read);
4053 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004054#else
4055 if ((fd = open(disk_device, O_RDONLY)) < 0)
4056 return 1;
4057 if (512 != read(fd, MBRbuffer, 512))
4058 return 1;
4059#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004060
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004061 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004062
4063 update_units();
4064
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004065#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004066 if (check_sun_label())
4067 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004068#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004069
4070#ifdef CONFIG_FEATURE_SGI_LABEL
4071 if (check_sgi_label())
4072 return 0;
4073#endif
4074
4075#ifdef CONFIG_FEATURE_AIX_LABEL
4076 if (check_aix_label())
4077 return 0;
4078#endif
4079
4080#ifdef CONFIG_FEATURE_OSF_LABEL
4081 if (check_osf_label()) {
4082 possibly_osf_label = 1;
4083 if (!valid_part_table_flag(MBRbuffer)) {
4084 osf_label = 1;
4085 return 0;
4086 }
4087 printf(_("This disk has both DOS and BSD magic.\n"
4088 "Give the 'b' command to go to BSD mode.\n"));
4089 }
4090#endif
4091
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004092#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004093got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004094#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004095
4096 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004097#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4098 return -1;
4099#else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004100 switch(what) {
4101 case fdisk:
4102 fprintf(stderr,
4103 _("Device contains neither a valid DOS "
4104 "partition table, nor Sun, SGI or OSF "
4105 "disklabel\n"));
4106#ifdef __sparc__
4107#ifdef CONFIG_FEATURE_SUN_LABEL
4108 create_sunlabel();
4109#endif
4110#else
4111 create_doslabel();
4112#endif
4113 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004114 case try_only:
4115 return -1;
4116 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004117#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004118 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004119#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004120 break;
4121 default:
4122 fprintf(stderr, _("Internal error\n"));
4123 exit(1);
4124 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004125#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004126 }
4127
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004128#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004129 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004130#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004131 warn_geometry();
4132
4133 for (i = 0; i < 4; i++) {
4134 struct pte *pe = &ptes[i];
4135
4136 if (IS_EXTENDED (pe->part_table->sys_ind)) {
4137 if (partitions != 4)
4138 fprintf(stderr, _("Ignoring extra extended "
4139 "partition %d\n"), i + 1);
4140 else
4141 read_extended(i);
4142 }
4143 }
4144
4145 for (i = 3; i < partitions; i++) {
4146 struct pte *pe = &ptes[i];
4147
4148 if (!valid_part_table_flag(pe->sectorbuffer)) {
4149 fprintf(stderr,
4150 _("Warning: invalid flag 0x%04x of partition "
4151 "table %d will be corrected by w(rite)\n"),
4152 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004153#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004154 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004155#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004156 }
4157 }
4158
4159 return 0;
4160}
4161
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004162#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004163/*
4164 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4165 * If the user hits Enter, DFLT is returned.
4166 * Answers like +10 are interpreted as offsets from BASE.
4167 *
4168 * There is no default if DFLT is not between LOW and HIGH.
4169 */
4170static uint
4171read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4172{
4173 uint i;
4174 int default_ok = 1;
4175 static char *ms = NULL;
4176 static int mslen = 0;
4177
4178 if (!ms || strlen(mesg)+100 > mslen) {
4179 mslen = strlen(mesg)+200;
4180 ms = xrealloc(ms,mslen);
4181 }
4182
4183 if (dflt < low || dflt > high)
4184 default_ok = 0;
4185
4186 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004187 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004188 mesg, low, high, dflt);
4189 else
Eric Andersen040f4402003-07-30 08:40:37 +00004190 snprintf(ms, mslen, "%s (%u-%u): ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004191 mesg, low, high);
4192
4193 while (1) {
4194 int use_default = default_ok;
4195
4196 /* ask question and read answer */
4197 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4198 && *line_ptr != '-' && *line_ptr != '+')
4199 continue;
4200
Eric Andersenc48d49a2003-07-03 10:02:32 +00004201 if (*line_ptr == '+' || *line_ptr == '-') {
4202 int minus = (*line_ptr == '-');
4203 int absolute = 0;
4204
4205 i = atoi(line_ptr+1);
4206
4207 while (isdigit(*++line_ptr))
4208 use_default = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004209
Eric Andersenc48d49a2003-07-03 10:02:32 +00004210 switch (*line_ptr) {
4211 case 'c':
4212 case 'C':
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004213 if (!display_in_cyl_units)
4214 i *= heads * sectors;
4215 break;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004216 case 'K':
Eric Andersen040f4402003-07-30 08:40:37 +00004217 absolute = 1024;
4218 break;
4219 case 'k':
Eric Andersenc48d49a2003-07-03 10:02:32 +00004220 absolute = 1000;
4221 break;
4222 case 'm':
4223 case 'M':
4224 absolute = 1000000;
4225 break;
4226 case 'g':
4227 case 'G':
4228 absolute = 1000000000;
4229 break;
4230 default:
4231 break;
4232 }
4233 if (absolute) {
4234 unsigned long long bytes;
4235 unsigned long unit;
4236
4237 bytes = (unsigned long long) i * absolute;
4238 unit = sector_size * units_per_sector;
4239 bytes += unit/2; /* round */
4240 bytes /= unit;
4241 i = bytes;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004242 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00004243 if (minus)
4244 i = -i;
4245 i += base;
4246 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004247 i = atoi(line_ptr);
4248 while (isdigit(*line_ptr)) {
4249 line_ptr++;
4250 use_default = 0;
4251 }
4252 }
4253 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004254 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004255 if (i >= low && i <= high)
4256 break;
4257 else
4258 printf(_("Value out of range.\n"));
4259 }
4260 return i;
4261}
4262
4263int
4264get_partition(int warn, int max) {
4265 struct pte *pe;
4266 int i;
4267
4268 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4269 pe = &ptes[i];
4270
4271 if (warn) {
4272 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4273#ifdef CONFIG_FEATURE_SUN_LABEL
4274 || (sun_label &&
4275 (!sunlabel->partitions[i].num_sectors ||
4276 !sunlabel->infos[i].id))
4277#endif
4278#ifdef CONFIG_FEATURE_SGI_LABEL
4279 || (sgi_label && (!sgi_get_num_sectors(i)))
4280#endif
4281 )
4282 fprintf(stderr,
4283 _("Warning: partition %d has empty type\n"),
4284 i+1);
4285 }
4286 return i;
4287}
4288
4289static int
4290get_existing_partition(int warn, int max) {
4291 int pno = -1;
4292 int i;
4293
4294 for (i = 0; i < max; i++) {
4295 struct pte *pe = &ptes[i];
4296 struct partition *p = pe->part_table;
4297
4298 if (p && !is_cleared_partition(p)) {
4299 if (pno >= 0)
4300 goto not_unique;
4301 pno = i;
4302 }
4303 }
4304 if (pno >= 0) {
4305 printf(_("Selected partition %d\n"), pno+1);
4306 return pno;
4307 }
4308 printf(_("No partition is defined yet!\n"));
4309 return -1;
4310
4311 not_unique:
4312 return get_partition(warn, max);
4313}
4314
4315static int
4316get_nonexisting_partition(int warn, int max) {
4317 int pno = -1;
4318 int i;
4319
4320 for (i = 0; i < max; i++) {
4321 struct pte *pe = &ptes[i];
4322 struct partition *p = pe->part_table;
4323
4324 if (p && is_cleared_partition(p)) {
4325 if (pno >= 0)
4326 goto not_unique;
4327 pno = i;
4328 }
4329 }
4330 if (pno >= 0) {
4331 printf(_("Selected partition %d\n"), pno+1);
4332 return pno;
4333 }
4334 printf(_("All primary partitions have been defined already!\n"));
4335 return -1;
4336
4337 not_unique:
4338 return get_partition(warn, max);
4339}
4340
4341
4342void change_units(void)
4343{
4344 display_in_cyl_units = !display_in_cyl_units;
4345 update_units();
4346 printf(_("Changing display/entry units to %s\n"),
4347 str_units(PLURAL));
4348}
4349
4350static void
4351toggle_active(int i) {
4352 struct pte *pe = &ptes[i];
4353 struct partition *p = pe->part_table;
4354
4355 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
4356 fprintf(stderr,
4357 _("WARNING: Partition %d is an extended partition\n"),
4358 i + 1);
4359 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4360 pe->changed = 1;
4361}
4362
4363static void
4364toggle_dos_compatibility_flag(void) {
4365 dos_compatible_flag = ~dos_compatible_flag;
4366 if (dos_compatible_flag) {
4367 sector_offset = sectors;
4368 printf(_("DOS Compatibility flag is set\n"));
4369 }
4370 else {
4371 sector_offset = 1;
4372 printf(_("DOS Compatibility flag is not set\n"));
4373 }
4374}
4375
4376static void
4377delete_partition(int i) {
4378 struct pte *pe = &ptes[i];
4379 struct partition *p = pe->part_table;
4380 struct partition *q = pe->ext_pointer;
4381
4382/* Note that for the fifth partition (i == 4) we don't actually
4383 * decrement partitions.
4384 */
4385
4386 if (warn_geometry())
4387 return; /* C/H/S not set */
4388 pe->changed = 1;
4389
4390#ifdef CONFIG_FEATURE_SUN_LABEL
4391 if (sun_label) {
4392 sun_delete_partition(i);
4393 return;
4394 }
4395#endif
4396#ifdef CONFIG_FEATURE_SGI_LABEL
4397 if (sgi_label) {
4398 sgi_delete_partition(i);
4399 return;
4400 }
4401#endif
4402
4403 if (i < 4) {
4404 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
4405 partitions = 4;
4406 ptes[ext_index].ext_pointer = NULL;
4407 extended_offset = 0;
4408 }
4409 clear_partition(p);
4410 return;
4411 }
4412
4413 if (!q->sys_ind && i > 4) {
4414 /* the last one in the chain - just delete */
4415 --partitions;
4416 --i;
4417 clear_partition(ptes[i].ext_pointer);
4418 ptes[i].changed = 1;
4419 } else {
4420 /* not the last one - further ones will be moved down */
4421 if (i > 4) {
4422 /* delete this link in the chain */
4423 p = ptes[i-1].ext_pointer;
4424 *p = *q;
4425 set_start_sect(p, get_start_sect(q));
4426 set_nr_sects(p, get_nr_sects(q));
4427 ptes[i-1].changed = 1;
4428 } else if (partitions > 5) { /* 5 will be moved to 4 */
4429 /* the first logical in a longer chain */
4430 pe = &ptes[5];
4431
4432 if (pe->part_table) /* prevent SEGFAULT */
4433 set_start_sect(pe->part_table,
4434 get_partition_start(pe) -
4435 extended_offset);
4436 pe->offset = extended_offset;
4437 pe->changed = 1;
4438 }
4439
4440 if (partitions > 5) {
4441 partitions--;
4442 while (i < partitions) {
4443 ptes[i] = ptes[i+1];
4444 i++;
4445 }
4446 } else
4447 /* the only logical: clear only */
4448 clear_partition(ptes[i].part_table);
4449 }
4450}
4451
4452static void
4453change_sysid(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004454 int i, sys, origsys;
4455 struct partition *p;
4456
Eric Andersen040f4402003-07-30 08:40:37 +00004457#ifdef CONFIG_FEATURE_SGI_LABEL
4458 /* If sgi_label then don't use get_existing_partition,
4459 let the user select a partition, since get_existing_partition()
4460 only works for Linux like partition tables. */
4461 if (!sgi_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004462 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004463 } else {
4464 i = get_partition(0, partitions);
4465 }
4466#else
4467 i = get_existing_partition(0, partitions);
4468#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004469 if (i == -1)
4470 return;
4471 p = ptes[i].part_table;
4472 origsys = sys = get_sysid(i);
4473
4474 /* if changing types T to 0 is allowed, then
4475 the reverse change must be allowed, too */
4476 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4477 printf(_("Partition %d does not exist yet!\n"), i + 1);
4478 else while (1) {
4479 sys = read_hex (get_sys_types());
4480
4481 if (!sys && !sgi_label && !sun_label) {
4482 printf(_("Type 0 means free space to many systems\n"
4483 "(but not to Linux). Having partitions of\n"
4484 "type 0 is probably unwise. You can delete\n"
4485 "a partition using the `d' command.\n"));
4486 /* break; */
4487 }
4488
4489 if (!sun_label && !sgi_label) {
4490 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
4491 printf(_("You cannot change a partition into"
4492 " an extended one or vice versa\n"
4493 "Delete it first.\n"));
4494 break;
4495 }
4496 }
4497
4498 if (sys < 256) {
4499#ifdef CONFIG_FEATURE_SUN_LABEL
4500 if (sun_label && i == 2 && sys != WHOLE_DISK)
4501 printf(_("Consider leaving partition 3 "
4502 "as Whole disk (5),\n"
4503 "as SunOS/Solaris expects it and "
4504 "even Linux likes it.\n\n"));
4505#endif
4506#ifdef CONFIG_FEATURE_SGI_LABEL
4507 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4508 || (i == 8 && sys != 0)))
4509 printf(_("Consider leaving partition 9 "
4510 "as volume header (0),\nand "
4511 "partition 11 as entire volume (6)"
4512 "as IRIX expects it.\n\n"));
4513#endif
4514 if (sys == origsys)
4515 break;
4516#ifdef CONFIG_FEATURE_SUN_LABEL
4517 if (sun_label) {
4518 sun_change_sysid(i, sys);
4519 } else
4520#endif
4521#ifdef CONFIG_FEATURE_SGI_LABEL
4522 if (sgi_label) {
4523 sgi_change_sysid(i, sys);
4524 } else
4525#endif
4526 p->sys_ind = sys;
4527 printf (_("Changed system type of partition %d "
4528 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004529 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004530 ptes[i].changed = 1;
4531 if (is_dos_partition(origsys) ||
4532 is_dos_partition(sys))
4533 dos_changed = 1;
4534 break;
4535 }
4536 }
4537}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004538#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4539
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004540
4541/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4542 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4543 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4544 * Lubkin Oct. 1991). */
4545
4546static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
4547 int spc = heads * sectors;
4548
4549 *c = ls / spc;
4550 ls = ls % spc;
4551 *h = ls / sectors;
4552 *s = ls % sectors + 1; /* sectors count from 1 */
4553}
4554
4555static void check_consistency(const struct partition *p, int partition) {
4556 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4557 uint pec, peh, pes; /* physical ending c, h, s */
4558 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4559 uint lec, leh, les; /* logical ending c, h, s */
4560
4561 if (!heads || !sectors || (partition >= 4))
4562 return; /* do not check extended partitions */
4563
4564/* physical beginning c, h, s */
4565 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4566 pbh = p->head;
4567 pbs = p->sector & 0x3f;
4568
4569/* physical ending c, h, s */
4570 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4571 peh = p->end_head;
4572 pes = p->end_sector & 0x3f;
4573
4574/* compute logical beginning (c, h, s) */
4575 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4576
4577/* compute logical ending (c, h, s) */
4578 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4579
4580/* Same physical / logical beginning? */
4581 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4582 printf(_("Partition %d has different physical/logical "
4583 "beginnings (non-Linux?):\n"), partition + 1);
4584 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4585 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4586 }
4587
4588/* Same physical / logical ending? */
4589 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4590 printf(_("Partition %d has different physical/logical "
4591 "endings:\n"), partition + 1);
4592 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4593 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4594 }
4595
4596#if 0
4597/* Beginning on cylinder boundary? */
4598 if (pbh != !pbc || pbs != 1) {
4599 printf(_("Partition %i does not start on cylinder "
4600 "boundary:\n"), partition + 1);
4601 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4602 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4603 }
4604#endif
4605
4606/* Ending on cylinder boundary? */
4607 if (peh != (heads - 1) || pes != sectors) {
Eric Andersenc48d49a2003-07-03 10:02:32 +00004608 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004609 partition + 1);
4610#if 0
4611 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4612 printf(_("should be (%d, %d, %d)\n"),
4613 pec, heads - 1, sectors);
4614#endif
4615 }
4616}
4617
4618static void
4619list_disk_geometry(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00004620 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004621 long megabytes = bytes/1000000;
4622
4623 if (megabytes < 10000)
4624 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4625 disk_device, megabytes, bytes);
4626 else
4627 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4628 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4629 printf(_("%d heads, %d sectors/track, %d cylinders"),
4630 heads, sectors, cylinders);
4631 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004632 printf(_(", total %llu sectors"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004633 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004634 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004635 str_units(PLURAL),
4636 units_per_sector, sector_size, units_per_sector * sector_size);
4637}
4638
4639/*
4640 * Check whether partition entries are ordered by their starting positions.
4641 * Return 0 if OK. Return i if partition i should have been earlier.
4642 * Two separate checks: primary and logical partitions.
4643 */
4644static int
4645wrong_p_order(int *prev) {
4646 const struct pte *pe;
4647 const struct partition *p;
4648 uint last_p_start_pos = 0, p_start_pos;
4649 int i, last_i = 0;
4650
4651 for (i = 0 ; i < partitions; i++) {
4652 if (i == 4) {
4653 last_i = 4;
4654 last_p_start_pos = 0;
4655 }
4656 pe = &ptes[i];
4657 if ((p = pe->part_table)->sys_ind) {
4658 p_start_pos = get_partition_start(pe);
4659
4660 if (last_p_start_pos > p_start_pos) {
4661 if (prev)
4662 *prev = last_i;
4663 return i;
4664 }
4665
4666 last_p_start_pos = p_start_pos;
4667 last_i = i;
4668 }
4669 }
4670 return 0;
4671}
4672
4673#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4674/*
4675 * Fix the chain of logicals.
4676 * extended_offset is unchanged, the set of sectors used is unchanged
4677 * The chain is sorted so that sectors increase, and so that
4678 * starting sectors increase.
4679 *
4680 * After this it may still be that cfdisk doesnt like the table.
4681 * (This is because cfdisk considers expanded parts, from link to
4682 * end of partition, and these may still overlap.)
4683 * Now
4684 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4685 * may help.
4686 */
4687static void
4688fix_chain_of_logicals(void) {
4689 int j, oj, ojj, sj, sjj;
4690 struct partition *pj,*pjj,tmp;
4691
4692 /* Stage 1: sort sectors but leave sector of part 4 */
4693 /* (Its sector is the global extended_offset.) */
4694 stage1:
4695 for (j = 5; j < partitions-1; j++) {
4696 oj = ptes[j].offset;
4697 ojj = ptes[j+1].offset;
4698 if (oj > ojj) {
4699 ptes[j].offset = ojj;
4700 ptes[j+1].offset = oj;
4701 pj = ptes[j].part_table;
4702 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4703 pjj = ptes[j+1].part_table;
4704 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4705 set_start_sect(ptes[j-1].ext_pointer,
4706 ojj-extended_offset);
4707 set_start_sect(ptes[j].ext_pointer,
4708 oj-extended_offset);
4709 goto stage1;
4710 }
4711 }
4712
4713 /* Stage 2: sort starting sectors */
4714 stage2:
4715 for (j = 4; j < partitions-1; j++) {
4716 pj = ptes[j].part_table;
4717 pjj = ptes[j+1].part_table;
4718 sj = get_start_sect(pj);
4719 sjj = get_start_sect(pjj);
4720 oj = ptes[j].offset;
4721 ojj = ptes[j+1].offset;
4722 if (oj+sj > ojj+sjj) {
4723 tmp = *pj;
4724 *pj = *pjj;
4725 *pjj = tmp;
4726 set_start_sect(pj, ojj+sjj-oj);
4727 set_start_sect(pjj, oj+sj-ojj);
4728 goto stage2;
4729 }
4730 }
4731
4732 /* Probably something was changed */
4733 for (j = 4; j < partitions; j++)
4734 ptes[j].changed = 1;
4735}
4736
4737
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004738static void
4739fix_partition_table_order(void) {
4740 struct pte *pei, *pek;
4741 int i,k;
4742
4743 if (!wrong_p_order(NULL)) {
4744 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4745 return;
4746 }
4747
4748 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4749 /* partition i should have come earlier, move it */
4750 /* We have to move data in the MBR */
4751 struct partition *pi, *pk, *pe, pbuf;
4752 pei = &ptes[i];
4753 pek = &ptes[k];
4754
4755 pe = pei->ext_pointer;
4756 pei->ext_pointer = pek->ext_pointer;
4757 pek->ext_pointer = pe;
4758
4759 pi = pei->part_table;
4760 pk = pek->part_table;
4761
4762 memmove(&pbuf, pi, sizeof(struct partition));
4763 memmove(pi, pk, sizeof(struct partition));
4764 memmove(pk, &pbuf, sizeof(struct partition));
4765
4766 pei->changed = pek->changed = 1;
4767 }
4768
4769 if (i)
4770 fix_chain_of_logicals();
4771
4772 printf("Done.\n");
4773
4774}
4775#endif
4776
4777static void
4778list_table(int xtra) {
4779 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004780 int i, w;
4781
4782#ifdef CONFIG_FEATURE_SUN_LABEL
4783 if (sun_label) {
4784 sun_list_table(xtra);
4785 return;
4786 }
4787#endif
4788
4789#ifdef CONFIG_FEATURE_SGI_LABEL
4790 if (sgi_label) {
4791 sgi_list_table(xtra);
4792 return;
4793 }
4794#endif
4795
4796 list_disk_geometry();
4797
4798#ifdef CONFIG_FEATURE_OSF_LABEL
4799 if (osf_label) {
4800 xbsd_print_disklabel(xtra);
4801 return;
4802 }
4803#endif
4804
4805 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4806 but if the device name ends in a digit, say /dev/foo1,
4807 then the partition is called /dev/foo1p3. */
4808 w = strlen(disk_device);
4809 if (w && isdigit(disk_device[w-1]))
4810 w++;
4811 if (w < 5)
4812 w = 5;
4813
4814 printf(_("%*s Boot Start End Blocks Id System\n"),
4815 w+1, _("Device"));
4816
4817 for (i = 0; i < partitions; i++) {
4818 const struct pte *pe = &ptes[i];
4819
4820 p = pe->part_table;
4821 if (p && !is_cleared_partition(p)) {
4822 unsigned int psects = get_nr_sects(p);
4823 unsigned int pblocks = psects;
4824 unsigned int podd = 0;
4825
4826 if (sector_size < 1024) {
4827 pblocks /= (1024 / sector_size);
4828 podd = psects % (1024 / sector_size);
4829 }
4830 if (sector_size > 1024)
4831 pblocks *= (sector_size / 1024);
4832 printf(
Eric Andersen040f4402003-07-30 08:40:37 +00004833 "%s %c %11lu %11lu %11lu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004834 partname(disk_device, i+1, w+2),
4835/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4836 ? '*' : '?',
Eric Andersen040f4402003-07-30 08:40:37 +00004837/* start */ (unsigned long) cround(get_partition_start(pe)),
4838/* end */ (unsigned long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004839 - (psects ? 1 : 0)),
Eric Andersen040f4402003-07-30 08:40:37 +00004840/* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004841/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004842/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004843 check_consistency(p, i);
4844 }
4845 }
4846
4847 /* Is partition table in disk order? It need not be, but... */
4848 /* partition table entries are not checked for correct order if this
4849 is a sgi, sun or aix labeled disk... */
4850 if (dos_label && wrong_p_order(NULL)) {
4851 printf(_("\nPartition table entries are not in disk order\n"));
4852 }
4853}
4854
4855#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4856static void
4857x_list_table(int extend) {
4858 const struct pte *pe;
4859 const struct partition *p;
4860 int i;
4861
4862 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4863 disk_device, heads, sectors, cylinders);
4864 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4865 for (i = 0 ; i < partitions; i++) {
4866 pe = &ptes[i];
4867 p = (extend ? pe->ext_pointer : pe->part_table);
4868 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004869 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004870 i + 1, p->boot_ind, p->head,
4871 sector(p->sector),
4872 cylinder(p->sector, p->cyl), p->end_head,
4873 sector(p->end_sector),
4874 cylinder(p->end_sector, p->end_cyl),
4875 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4876 if (p->sys_ind)
4877 check_consistency(p, i);
4878 }
4879 }
4880}
4881#endif
4882
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004883#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004884static void
4885fill_bounds(uint *first, uint *last) {
4886 int i;
4887 const struct pte *pe = &ptes[0];
4888 const struct partition *p;
4889
4890 for (i = 0; i < partitions; pe++,i++) {
4891 p = pe->part_table;
4892 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
4893 first[i] = 0xffffffff;
4894 last[i] = 0;
4895 } else {
4896 first[i] = get_partition_start(pe);
4897 last[i] = first[i] + get_nr_sects(p) - 1;
4898 }
4899 }
4900}
4901
4902static void
4903check(int n, uint h, uint s, uint c, uint start) {
4904 uint total, real_s, real_c;
4905
4906 real_s = sector(s) - 1;
4907 real_c = cylinder(s, c);
4908 total = (real_c * sectors + real_s) * heads + h;
4909 if (!total)
4910 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4911 if (h >= heads)
4912 fprintf(stderr,
4913 _("Partition %d: head %d greater than maximum %d\n"),
4914 n, h + 1, heads);
4915 if (real_s >= sectors)
4916 fprintf(stderr, _("Partition %d: sector %d greater than "
4917 "maximum %d\n"), n, s, sectors);
4918 if (real_c >= cylinders)
4919 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
4920 "maximum %d\n"), n, real_c + 1, cylinders);
4921 if (cylinders <= 1024 && start != total)
4922 fprintf(stderr,
4923 _("Partition %d: previous sectors %d disagrees with "
4924 "total %d\n"), n, start, total);
4925}
4926
4927static void
4928verify(void) {
4929 int i, j;
4930 uint total = 1;
4931 uint first[partitions], last[partitions];
4932 struct partition *p;
4933
4934 if (warn_geometry())
4935 return;
4936
4937#ifdef CONFIG_FEATURE_SUN_LABEL
4938 if (sun_label) {
4939 verify_sun();
4940 return;
4941 }
4942#endif
4943#ifdef CONFIG_FEATURE_SGI_LABEL
4944 if (sgi_label) {
4945 verify_sgi(1);
4946 return;
4947 }
4948#endif
4949
4950 fill_bounds(first, last);
4951 for (i = 0; i < partitions; i++) {
4952 struct pte *pe = &ptes[i];
4953
4954 p = pe->part_table;
4955 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
4956 check_consistency(p, i);
4957 if (get_partition_start(pe) < first[i])
4958 printf(_("Warning: bad start-of-data in "
4959 "partition %d\n"), i + 1);
4960 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4961 last[i]);
4962 total += last[i] + 1 - first[i];
4963 for (j = 0; j < i; j++)
4964 if ((first[i] >= first[j] && first[i] <= last[j])
4965 || ((last[i] <= last[j] && last[i] >= first[j]))) {
4966 printf(_("Warning: partition %d overlaps "
4967 "partition %d.\n"), j + 1, i + 1);
4968 total += first[i] >= first[j] ?
4969 first[i] : first[j];
4970 total -= last[i] <= last[j] ?
4971 last[i] : last[j];
4972 }
4973 }
4974 }
4975
4976 if (extended_offset) {
4977 struct pte *pex = &ptes[ext_index];
4978 uint e_last = get_start_sect(pex->part_table) +
4979 get_nr_sects(pex->part_table) - 1;
4980
4981 for (i = 4; i < partitions; i++) {
4982 total++;
4983 p = ptes[i].part_table;
4984 if (!p->sys_ind) {
4985 if (i != 4 || i + 1 < partitions)
4986 printf(_("Warning: partition %d "
4987 "is empty\n"), i + 1);
4988 }
4989 else if (first[i] < extended_offset ||
4990 last[i] > e_last)
4991 printf(_("Logical partition %d not entirely in "
4992 "partition %d\n"), i + 1, ext_index + 1);
4993 }
4994 }
4995
4996 if (total > heads * sectors * cylinders)
4997 printf(_("Total allocated sectors %d greater than the maximum "
4998 "%d\n"), total, heads * sectors * cylinders);
4999 else if ((total = heads * sectors * cylinders - total) != 0)
5000 printf(_("%d unallocated sectors\n"), total);
5001}
5002
5003static void
5004add_partition(int n, int sys) {
5005 char mesg[256]; /* 48 does not suffice in Japanese */
5006 int i, readed = 0;
5007 struct partition *p = ptes[n].part_table;
5008 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005009 long long llimit;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005010 uint start, stop = 0, limit, temp,
5011 first[partitions], last[partitions];
5012
5013 if (p && p->sys_ind) {
5014 printf(_("Partition %d is already defined. Delete "
5015 "it before re-adding it.\n"), n + 1);
5016 return;
5017 }
5018 fill_bounds(first, last);
5019 if (n < 4) {
5020 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005021 if (display_in_cyl_units || !total_number_of_sectors)
5022 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005023 else
Eric Andersen040f4402003-07-30 08:40:37 +00005024 llimit = total_number_of_sectors - 1;
5025 limit = llimit;
5026 if (limit != llimit)
5027 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005028 if (extended_offset) {
5029 first[ext_index] = extended_offset;
5030 last[ext_index] = get_start_sect(q) +
5031 get_nr_sects(q) - 1;
5032 }
5033 } else {
5034 start = extended_offset + sector_offset;
5035 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5036 }
5037 if (display_in_cyl_units)
5038 for (i = 0; i < partitions; i++)
5039 first[i] = (cround(first[i]) - 1) * units_per_sector;
5040
5041 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5042 do {
5043 temp = start;
5044 for (i = 0; i < partitions; i++) {
5045 int lastplusoff;
5046
5047 if (start == ptes[i].offset)
5048 start += sector_offset;
5049 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
5050 if (start >= first[i] && start <= lastplusoff)
5051 start = lastplusoff + 1;
5052 }
5053 if (start > limit)
5054 break;
5055 if (start >= temp+units_per_sector && readed) {
5056 printf(_("Sector %d is already allocated\n"), temp);
5057 temp = start;
5058 readed = 0;
5059 }
5060 if (!readed && start == temp) {
5061 uint saved_start;
5062
5063 saved_start = start;
5064 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5065 0, mesg);
5066 if (display_in_cyl_units) {
5067 start = (start - 1) * units_per_sector;
5068 if (start < saved_start) start = saved_start;
5069 }
5070 readed = 1;
5071 }
5072 } while (start != temp || !readed);
5073 if (n > 4) { /* NOT for fifth partition */
5074 struct pte *pe = &ptes[n];
5075
5076 pe->offset = start - sector_offset;
5077 if (pe->offset == extended_offset) { /* must be corrected */
5078 pe->offset++;
5079 if (sector_offset == 1)
5080 start++;
5081 }
5082 }
5083
5084 for (i = 0; i < partitions; i++) {
5085 struct pte *pe = &ptes[i];
5086
5087 if (start < pe->offset && limit >= pe->offset)
5088 limit = pe->offset - 1;
5089 if (start < first[i] && limit >= first[i])
5090 limit = first[i] - 1;
5091 }
5092 if (start > limit) {
5093 printf(_("No free sectors available\n"));
5094 if (n > 4)
5095 partitions--;
5096 return;
5097 }
5098 if (cround(start) == cround(limit)) {
5099 stop = limit;
5100 } else {
5101 snprintf(mesg, sizeof(mesg),
5102 _("Last %s or +size or +sizeM or +sizeK"),
5103 str_units(SINGULAR));
5104 stop = read_int(cround(start), cround(limit), cround(limit),
5105 cround(start), mesg);
5106 if (display_in_cyl_units) {
5107 stop = stop * units_per_sector - 1;
5108 if (stop >limit)
5109 stop = limit;
5110 }
5111 }
5112
5113 set_partition(n, 0, start, stop, sys);
5114 if (n > 4)
5115 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5116
5117 if (IS_EXTENDED (sys)) {
5118 struct pte *pe4 = &ptes[4];
5119 struct pte *pen = &ptes[n];
5120
5121 ext_index = n;
5122 pen->ext_pointer = p;
5123 pe4->offset = extended_offset = start;
5124 pe4->sectorbuffer = xcalloc(1, sector_size);
5125 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5126 pe4->ext_pointer = pe4->part_table + 1;
5127 pe4->changed = 1;
5128 partitions = 5;
5129 }
5130}
5131
5132static void
5133add_logical(void) {
5134 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5135 struct pte *pe = &ptes[partitions];
5136
5137 pe->sectorbuffer = xcalloc(1, sector_size);
5138 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5139 pe->ext_pointer = pe->part_table + 1;
5140 pe->offset = 0;
5141 pe->changed = 1;
5142 partitions++;
5143 }
5144 add_partition(partitions - 1, LINUX_NATIVE);
5145}
5146
5147static void
5148new_partition(void) {
5149 int i, free_primary = 0;
5150
5151 if (warn_geometry())
5152 return;
5153
5154#ifdef CONFIG_FEATURE_SUN_LABEL
5155 if (sun_label) {
5156 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5157 return;
5158 }
5159#endif
5160#ifdef CONFIG_FEATURE_SGI_LABEL
5161 if (sgi_label) {
5162 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5163 return;
5164 }
5165#endif
5166#ifdef CONFIG_FEATURE_AIX_LABEL
5167 if (aix_label) {
5168 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5169 "\n\tIf you want to add DOS-type partitions, create"
5170 "\n\ta new empty DOS partition table first. (Use o.)"
5171 "\n\tWARNING: "
5172 "This will destroy the present disk contents.\n"));
5173 return;
5174 }
5175#endif
5176
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005177 for (i = 0; i < 4; i++)
5178 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005179
5180 if (!free_primary && partitions >= MAXIMUM_PARTS) {
5181 printf(_("The maximum number of partitions has been created\n"));
5182 return;
5183 }
5184
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005185 if (!free_primary) {
5186 if (extended_offset)
5187 add_logical();
5188 else
5189 printf(_("You must delete some partition and add "
5190 "an extended partition first\n"));
5191 } else {
5192 char c, line[LINE_LENGTH];
5193 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5194 "partition (1-4)\n",
5195 "Command action", (extended_offset ?
5196 "l logical (5 or over)" : "e extended"));
5197 while (1) {
5198 if ((c = read_char(line)) == 'p' || c == 'P') {
5199 i = get_nonexisting_partition(0, 4);
5200 if (i >= 0)
5201 add_partition(i, LINUX_NATIVE);
5202 return;
5203 }
5204 else if (c == 'l' && extended_offset) {
5205 add_logical();
5206 return;
5207 }
5208 else if (c == 'e' && !extended_offset) {
5209 i = get_nonexisting_partition(0, 4);
5210 if (i >= 0)
5211 add_partition(i, EXTENDED);
5212 return;
5213 }
5214 else
5215 printf(_("Invalid partition number "
5216 "for type `%c'\n"), c);
5217 }
5218 }
5219}
5220
5221static void
5222write_table(void) {
5223 int i;
5224
5225 if (dos_label) {
5226 for (i=0; i<3; i++)
5227 if (ptes[i].changed)
5228 ptes[3].changed = 1;
5229 for (i = 3; i < partitions; i++) {
5230 struct pte *pe = &ptes[i];
5231
5232 if (pe->changed) {
5233 write_part_table_flag(pe->sectorbuffer);
5234 write_sector(pe->offset, pe->sectorbuffer);
5235 }
5236 }
5237 }
5238#ifdef CONFIG_FEATURE_SGI_LABEL
5239 else if (sgi_label) {
5240 /* no test on change? the printf below might be mistaken */
5241 sgi_write_table();
5242 }
5243#endif
5244#ifdef CONFIG_FEATURE_SUN_LABEL
5245 else if (sun_label) {
5246 int needw = 0;
5247
5248 for (i=0; i<8; i++)
5249 if (ptes[i].changed)
5250 needw = 1;
5251 if (needw)
5252 sun_write_table();
5253 }
5254#endif
5255
5256 printf(_("The partition table has been altered!\n\n"));
5257 reread_partition_table(1);
5258}
5259
5260void
5261reread_partition_table(int leave) {
5262 int error = 0;
5263 int i;
5264
5265 printf(_("Calling ioctl() to re-read partition table.\n"));
5266 sync();
5267 sleep(2);
5268 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5269 error = errno;
5270 } else {
5271 /* some kernel versions (1.2.x) seem to have trouble
5272 rereading the partition table, but if asked to do it
5273 twice, the second time works. - biro@yggdrasil.com */
5274 sync();
5275 sleep(2);
5276 if ((i = ioctl(fd, BLKRRPART)) != 0)
5277 error = errno;
5278 }
5279
5280 if (i) {
5281 printf(_("\nWARNING: Re-reading the partition table "
5282 "failed with error %d: %s.\n"
5283 "The kernel still uses the old table.\n"
5284 "The new table will be used "
5285 "at the next reboot.\n"),
5286 error, strerror(error));
5287 }
5288
5289 if (dos_changed)
5290 printf(
5291 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5292 "partitions, please see the fdisk manual page for additional\n"
5293 "information.\n"));
5294
5295 if (leave) {
5296 close(fd);
5297
5298 printf(_("Syncing disks.\n"));
5299 sync();
5300 sleep(4); /* for sync() */
5301 exit(!!i);
5302 }
5303}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005304#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005305
5306#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5307#define MAX_PER_LINE 16
5308static void
5309print_buffer(char pbuffer[]) {
5310 int i,
5311 l;
5312
5313 for (i = 0, l = 0; i < sector_size; i++, l++) {
5314 if (l == 0)
5315 printf("0x%03X:", i);
5316 printf(" %02X", (unsigned char) pbuffer[i]);
5317 if (l == MAX_PER_LINE - 1) {
5318 printf("\n");
5319 l = -1;
5320 }
5321 }
5322 if (l > 0)
5323 printf("\n");
5324 printf("\n");
5325}
5326
5327
5328static void
5329print_raw(void) {
5330 int i;
5331
5332 printf(_("Device: %s\n"), disk_device);
5333#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5334 if (sun_label || sgi_label)
5335 print_buffer(MBRbuffer);
5336 else
5337#endif
5338 for (i = 3; i < partitions; i++)
5339 print_buffer(ptes[i].sectorbuffer);
5340}
5341
5342static void
5343move_begin(int i) {
5344 struct pte *pe = &ptes[i];
5345 struct partition *p = pe->part_table;
5346 uint new, first;
5347
5348 if (warn_geometry())
5349 return;
5350 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
5351 printf(_("Partition %d has no data area\n"), i + 1);
5352 return;
5353 }
5354 first = get_partition_start(pe);
5355 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5356 _("New beginning of data")) - pe->offset;
5357
5358 if (new != get_nr_sects(p)) {
5359 first = get_nr_sects(p) + get_start_sect(p) - new;
5360 set_nr_sects(p, first);
5361 set_start_sect(p, new);
5362 pe->changed = 1;
5363 }
5364}
5365
5366static void
5367xselect(void) {
5368 char c;
5369
5370 while(1) {
5371 putchar('\n');
5372 c = tolower(read_char(_("Expert command (m for help): ")));
5373 switch (c) {
5374 case 'a':
5375#ifdef CONFIG_FEATURE_SUN_LABEL
5376 if (sun_label)
5377 sun_set_alt_cyl();
5378#endif
5379 break;
5380 case 'b':
5381 if (dos_label)
5382 move_begin(get_partition(0, partitions));
5383 break;
5384 case 'c':
5385 user_cylinders = cylinders =
5386 read_int(1, cylinders, 1048576, 0,
5387 _("Number of cylinders"));
5388#ifdef CONFIG_FEATURE_SUN_LABEL
5389 if (sun_label)
5390 sun_set_ncyl(cylinders);
5391#endif
5392 if (dos_label)
5393 warn_cylinders();
5394 break;
5395 case 'd':
5396 print_raw();
5397 break;
5398 case 'e':
5399#ifdef CONFIG_FEATURE_SGI_LABEL
5400 if (sgi_label)
5401 sgi_set_xcyl();
5402 else
5403#endif
5404#ifdef CONFIG_FEATURE_SUN_LABEL
5405 if (sun_label)
5406 sun_set_xcyl();
5407 else
5408#endif
5409 if (dos_label)
5410 x_list_table(1);
5411 break;
5412 case 'f':
5413 if (dos_label)
5414 fix_partition_table_order();
5415 break;
5416 case 'g':
5417#ifdef CONFIG_FEATURE_SGI_LABEL
5418 create_sgilabel();
5419#endif
5420 break;
5421 case 'h':
5422 user_heads = heads = read_int(1, heads, 256, 0,
5423 _("Number of heads"));
5424 update_units();
5425 break;
5426 case 'i':
5427#ifdef CONFIG_FEATURE_SUN_LABEL
5428 if (sun_label)
5429 sun_set_ilfact();
5430#endif
5431 break;
5432 case 'o':
5433#ifdef CONFIG_FEATURE_SUN_LABEL
5434 if (sun_label)
5435 sun_set_rspeed();
5436#endif
5437 break;
5438 case 'p':
5439#ifdef CONFIG_FEATURE_SUN_LABEL
5440 if (sun_label)
5441 list_table(1);
5442 else
5443#endif
5444 x_list_table(0);
5445 break;
5446 case 'q':
5447 close(fd);
5448 printf("\n");
5449 exit(0);
5450 case 'r':
5451 return;
5452 case 's':
5453 user_sectors = sectors = read_int(1, sectors, 63, 0,
5454 _("Number of sectors"));
5455 if (dos_compatible_flag) {
5456 sector_offset = sectors;
5457 fprintf(stderr, _("Warning: setting "
5458 "sector offset for DOS "
5459 "compatiblity\n"));
5460 }
5461 update_units();
5462 break;
5463 case 'v':
5464 verify();
5465 break;
5466 case 'w':
5467 write_table(); /* does not return */
5468 break;
5469 case 'y':
5470#ifdef CONFIG_FEATURE_SUN_LABEL
5471 if (sun_label)
5472 sun_set_pcylcount();
5473#endif
5474 break;
5475 default:
5476 xmenu();
5477 }
5478 }
5479}
5480#endif /* ADVANCED mode */
5481
5482static int
5483is_ide_cdrom_or_tape(const char *device) {
5484 FILE *procf;
5485 char buf[100];
5486 struct stat statbuf;
5487 int is_ide = 0;
5488
5489 /* No device was given explicitly, and we are trying some
5490 likely things. But opening /dev/hdc may produce errors like
5491 "hdc: tray open or drive not ready"
5492 if it happens to be a CD-ROM drive. It even happens that
5493 the process hangs on the attempt to read a music CD.
5494 So try to be careful. This only works since 2.1.73. */
5495
5496 if (strncmp("/dev/hd", device, 7))
5497 return 0;
5498
5499 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5500 procf = fopen(buf, "r");
5501 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5502 is_ide = (!strncmp(buf, "cdrom", 5) ||
5503 !strncmp(buf, "tape", 4));
5504 else
5505 /* Now when this proc file does not exist, skip the
5506 device when it is read-only. */
5507 if (stat(device, &statbuf) == 0)
5508 is_ide = ((statbuf.st_mode & 0222) == 0);
5509
5510 if (procf)
5511 fclose(procf);
5512 return is_ide;
5513}
5514
5515static void
5516try(const char *device, int user_specified) {
5517 int gb;
5518
5519 disk_device = device;
5520 if (setjmp(listingbuf))
5521 return;
5522 if (!user_specified)
5523 if (is_ide_cdrom_or_tape(device))
5524 return;
5525 if ((fd = open(disk_device, type_open)) >= 0) {
5526 gb = get_boot(try_only);
5527 if (gb > 0) { /* I/O error */
5528 close(fd);
5529 } else if (gb < 0) { /* no DOS signature */
5530 list_disk_geometry();
5531 if (aix_label)
5532 return;
5533#ifdef CONFIG_FEATURE_OSF_LABEL
5534 if (btrydev(device) < 0)
5535#endif
5536 fprintf(stderr,
5537 _("Disk %s doesn't contain a valid "
5538 "partition table\n"), device);
5539 close(fd);
5540 } else {
5541 close(fd);
5542 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005543#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005544 if (!sun_label && partitions > 4)
5545 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005546#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005547 }
5548 } else {
5549 /* Ignore other errors, since we try IDE
5550 and SCSI hard disks which may not be
5551 installed on the system. */
5552 if (errno == EACCES) {
5553 fprintf(stderr, _("Cannot open %s\n"), device);
5554 return;
5555 }
5556 }
5557}
5558
5559/* for fdisk -l: try all things in /proc/partitions
5560 that look like a partition name (do not end in a digit) */
5561static void
5562tryprocpt(void) {
5563 FILE *procpt;
5564 char line[100], ptname[100], devname[120], *s;
5565 int ma, mi, sz;
5566
Manuel Novoa III cad53642003-03-19 09:13:01 +00005567 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005568
5569 while (fgets(line, sizeof(line), procpt)) {
5570 if (sscanf (line, " %d %d %d %[^\n ]",
5571 &ma, &mi, &sz, ptname) != 4)
5572 continue;
5573 for (s = ptname; *s; s++);
5574 if (isdigit(s[-1]))
5575 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005576 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005577 try(devname, 0);
5578 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005579#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005580 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005581#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005582}
5583
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005584#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005585static void
5586unknown_command(int c) {
5587 printf(_("%c: unknown command\n"), c);
5588}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005589#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005590
5591int fdisk_main(int argc, char **argv) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005592 int c;
5593#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5594 int optl = 0;
5595#endif
5596#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5597 int opts = 0;
5598#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005599 /*
5600 * Calls:
5601 * fdisk -v
5602 * fdisk -l [-b sectorsize] [-u] device ...
5603 * fdisk -s [partition] ...
5604 * fdisk [-b sectorsize] [-u] device
5605 *
5606 * Options -C, -H, -S set the geometry.
5607 *
5608 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005609 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5610#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5611 "s"
5612#endif
5613 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005614 switch (c) {
5615 case 'b':
5616 /* Ugly: this sector size is really per device,
5617 so cannot be combined with multiple disks,
5618 and te same goes for the C/H/S options.
5619 */
5620 sector_size = atoi(optarg);
5621 if (sector_size != 512 && sector_size != 1024 &&
5622 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005623 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005624 sector_offset = 2;
5625 user_set_sector_size = 1;
5626 break;
5627 case 'C':
5628 user_cylinders = atoi(optarg);
5629 break;
5630 case 'H':
5631 user_heads = atoi(optarg);
5632 if (user_heads <= 0 || user_heads >= 256)
5633 user_heads = 0;
5634 break;
5635 case 'S':
5636 user_sectors = atoi(optarg);
5637 if (user_sectors <= 0 || user_sectors >= 64)
5638 user_sectors = 0;
5639 break;
5640 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005641#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005642 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005643#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005644 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005645#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005646 case 's':
5647 opts = 1;
5648 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005649#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005650 case 'u':
5651 display_in_cyl_units = 0;
5652 break;
5653 case 'V':
5654 case 'v':
5655 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5656 return 0;
5657 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005658 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005659 }
5660 }
5661
5662#if 0
5663 printf(_("This kernel finds the sector size itself - "
5664 "-b option ignored\n"));
5665#else
5666 if (user_set_sector_size && argc-optind != 1)
5667 printf(_("Warning: the -b (set sector size) option should"
5668 " be used with one specified device\n"));
5669#endif
5670
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005671#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005672 if (optl) {
5673 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005674#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005675 type_open = O_RDONLY;
5676 if (argc > optind) {
5677 int k;
5678#if __GNUC__
5679 /* avoid gcc warning:
5680 variable `k' might be clobbered by `longjmp' */
5681 (void)&k;
5682#endif
5683 listing = 1;
5684 for (k=optind; k<argc; k++)
5685 try(argv[k], 1);
5686 } else {
5687 /* we no longer have default device names */
5688 /* but, we can use /proc/partitions instead */
5689 tryprocpt();
5690 }
5691 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005692#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005693 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005694#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005695
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005696#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005697 if (opts) {
5698 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005699 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005700
5701 nowarn = 1;
5702 type_open = O_RDONLY;
5703
5704 opts = argc - optind;
5705 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005706 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005707
5708 for (j = optind; j < argc; j++) {
5709 disk_device = argv[j];
5710 if ((fd = open(disk_device, type_open)) < 0)
5711 fdisk_fatal(unable_to_open);
5712 if (ioctl(fd, BLKGETSIZE, &size))
5713 fdisk_fatal(ioctl_error);
5714 close(fd);
5715 if (opts == 1)
5716 printf("%ld\n", size/2);
5717 else
5718 printf("%s: %ld\n", argv[j], size/2);
5719 }
5720 return 0;
5721 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005722#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005723
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005724#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005725 if (argc-optind == 1)
5726 disk_device = argv[optind];
5727 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005728 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005729
5730 get_boot(fdisk);
5731
5732#ifdef CONFIG_FEATURE_OSF_LABEL
5733 if (osf_label) {
5734 /* OSF label, and no DOS label */
5735 printf(_("Detected an OSF/1 disklabel on %s, entering "
5736 "disklabel mode.\n"),
5737 disk_device);
5738 bselect();
5739 osf_label = 0;
5740 /* If we return we may want to make an empty DOS label? */
5741 }
5742#endif
5743
5744 while (1) {
5745 putchar('\n');
5746 c = tolower(read_char(_("Command (m for help): ")));
5747 switch (c) {
5748 case 'a':
5749 if (dos_label)
5750 toggle_active(get_partition(1, partitions));
5751#ifdef CONFIG_FEATURE_SUN_LABEL
5752 else if (sun_label)
5753 toggle_sunflags(get_partition(1, partitions),
5754 0x01);
5755#endif
5756#ifdef CONFIG_FEATURE_SGI_LABEL
5757 else if (sgi_label)
5758 sgi_set_bootpartition(
5759 get_partition(1, partitions));
5760#endif
5761 else
5762 unknown_command(c);
5763 break;
5764 case 'b':
5765#ifdef CONFIG_FEATURE_SGI_LABEL
5766 if (sgi_label) {
5767 printf(_("\nThe current boot file is: %s\n"),
5768 sgi_get_bootfile());
5769 if (read_chars(_("Please enter the name of the "
5770 "new boot file: ")) == '\n')
5771 printf(_("Boot file unchanged\n"));
5772 else
5773 sgi_set_bootfile(line_ptr);
5774 } else
5775#endif
5776#ifdef CONFIG_FEATURE_OSF_LABEL
5777 bselect();
5778#endif
5779 break;
5780 case 'c':
5781 if (dos_label)
5782 toggle_dos_compatibility_flag();
5783#ifdef CONFIG_FEATURE_SUN_LABEL
5784 else if (sun_label)
5785 toggle_sunflags(get_partition(1, partitions),
5786 0x10);
5787#endif
5788#ifdef CONFIG_FEATURE_SGI_LABEL
5789 else if (sgi_label)
5790 sgi_set_swappartition(
5791 get_partition(1, partitions));
5792#endif
5793 else
5794 unknown_command(c);
5795 break;
5796 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005797 {
Eric Andersen040f4402003-07-30 08:40:37 +00005798 int j;
5799#ifdef CONFIG_FEATURE_SGI_LABEL
5800 /* If sgi_label then don't use get_existing_partition,
5801 let the user select a partition, since
5802 get_existing_partition() only works for Linux-like
5803 partition tables */
5804 if (!sgi_label) {
5805 j = get_existing_partition(1, partitions);
5806 } else {
5807 j = get_partition(1, partitions);
5808 }
5809#else
5810 j = get_existing_partition(1, partitions);
5811#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005812 if (j >= 0)
5813 delete_partition(j);
5814 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005815 break;
5816 case 'i':
5817#ifdef CONFIG_FEATURE_SGI_LABEL
5818 if (sgi_label)
5819 create_sgiinfo();
5820 else
5821#endif
5822 unknown_command(c);
5823 case 'l':
5824 list_types(get_sys_types());
5825 break;
5826 case 'm':
5827 menu();
5828 break;
5829 case 'n':
5830 new_partition();
5831 break;
5832 case 'o':
5833 create_doslabel();
5834 break;
5835 case 'p':
5836 list_table(0);
5837 break;
5838 case 'q':
5839 close(fd);
5840 printf("\n");
5841 return 0;
5842 case 's':
5843#ifdef CONFIG_FEATURE_SUN_LABEL
5844 create_sunlabel();
5845#endif
5846 break;
5847 case 't':
5848 change_sysid();
5849 break;
5850 case 'u':
5851 change_units();
5852 break;
5853 case 'v':
5854 verify();
5855 break;
5856 case 'w':
5857 write_table(); /* does not return */
5858 break;
5859#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5860 case 'x':
5861#ifdef CONFIG_FEATURE_SGI_LABEL
5862 if (sgi_label) {
5863 fprintf(stderr,
5864 _("\n\tSorry, no experts menu for SGI "
5865 "partition tables available.\n\n"));
5866 } else
5867#endif
5868
5869 xselect();
5870 break;
5871#endif
5872 default:
5873 unknown_command(c);
5874 menu();
5875 }
5876 }
5877 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005878#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005879}