blob: 4fecbbb8936343eaefd702bbc8a0d1d484568610 [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 Andersen040f4402003-07-30 08:40:37 +000013#define UTIL_LINUX_VERSION "2.12pre"
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>
29
30#include <endian.h>
31#define u_char unsigned char
32#include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */
33#undef u_char
34
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000035#include <sys/ioctl.h>
36#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000037#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000038
Eric Andersenacd244a2002-12-11 03:49:33 +000039#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
40
41/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000042#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000043
44#include <sys/utsname.h>
45
46#include "busybox.h"
47
48#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
49
50#define DKTYPENAMES
51
52#define _(Text) Text
53
54#define BLKRRPART _IO(0x12,95) /* re-read partition table */
55#define BLKGETSIZE _IO(0x12,96) /* return device size */
56#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
57#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersen040f4402003-07-30 08:40:37 +000058#define BLKGETSIZE64 _IOR(0x12,114,8) /* 8 = sizeof(u64) */
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
91#if defined(__GNUC__) || defined(HAS_LONG_LONG)
92typedef long long ext2_loff_t;
93#else
94typedef long ext2_loff_t;
95#endif
96
97/* including <linux/hdreg.h> also fails */
98struct hd_geometry {
99 unsigned char heads;
100 unsigned char sectors;
101 unsigned short cylinders;
102 unsigned long start;
103};
104
105#define HDIO_GETGEO 0x0301 /* get device geometry */
106
107
108struct systypes {
109 const unsigned char *name;
110};
111
Eric Andersen040f4402003-07-30 08:40:37 +0000112static uint sector_size = DEFAULT_SECTOR_SIZE,
113 user_set_sector_size,
114 sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000115
116/*
117 * Raw disk label. For DOS-type partition tables the MBR,
118 * with descriptions of the primary partitions.
119 */
120static char MBRbuffer[MAX_SECTOR_SIZE];
121
122#ifdef CONFIG_FEATURE_SUN_LABEL
123static int sun_label; /* looking at sun disklabel */
124#else
125#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000126#endif
127#ifdef CONFIG_FEATURE_SGI_LABEL
128static int sgi_label; /* looking at sgi disklabel */
129#else
130#define sgi_label 0
131#endif
132#ifdef CONFIG_FEATURE_AIX_LABEL
133static int aix_label; /* looking at aix disklabel */
134#else
135#define aix_label 0
136#endif
137#ifdef CONFIG_FEATURE_OSF_LABEL
138static int osf_label; /* looking at OSF/1 disklabel */
139static int possibly_osf_label;
140#else
141#define osf_label 0
142#endif
143
144#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
145
146static uint heads, sectors, cylinders;
147static void update_units(void);
148
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000149
150/*
151 * return partition name - uses static storage unless buf is supplied
152 */
153static const char *
154partname(const char *dev, int pno, int lth) {
155 static char buffer[80];
156 const char *p;
157 int w, wp;
158 int bufsiz;
159 char *bufp;
160
161 bufp = buffer;
162 bufsiz = sizeof(buffer);
163
164 w = strlen(dev);
165 p = "";
166
167 if (isdigit(dev[w-1]))
168 p = "p";
169
170 /* devfs kludge - note: fdisk partition names are not supposed
171 to equal kernel names, so there is no reason to do this */
172 if (strcmp (dev + w - 4, "disc") == 0) {
173 w -= 4;
174 p = "part";
175 }
176
177 wp = strlen(p);
178
179 if (lth) {
180 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
181 lth-wp-2, w, dev, p, pno);
182 } else {
183 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
184 }
185 return bufp;
186}
187
188struct partition {
189 unsigned char boot_ind; /* 0x80 - active */
190 unsigned char head; /* starting head */
191 unsigned char sector; /* starting sector */
192 unsigned char cyl; /* starting cylinder */
193 unsigned char sys_ind; /* What partition type */
194 unsigned char end_head; /* end head */
195 unsigned char end_sector; /* end sector */
196 unsigned char end_cyl; /* end cylinder */
197 unsigned char start4[4]; /* starting sector counting from 0 */
198 unsigned char size4[4]; /* nr of sectors in partition */
199};
200
201enum failure {
202 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
203 unable_to_write
204};
205
206enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
207
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000208static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000209static int fd; /* the disk */
210static int partitions = 4; /* maximum partition + 1 */
211static uint display_in_cyl_units = 1;
212static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000213#ifdef CONFIG_FEATURE_FDISK_WRITABLE
214static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000215static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000216static void reread_partition_table(int leave);
217static void delete_partition(int i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000218static int get_partition(int warn, int max);
219static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000220static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000221#endif
222static const char *partition_type(unsigned char type);
223static void fdisk_fatal(enum failure why) __attribute__ ((noreturn));
224static void get_geometry(void);
225static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000226
227#define PLURAL 0
228#define SINGULAR 1
229
230#define hex_val(c) ({ \
231 char _c = (c); \
232 isdigit(_c) ? _c - '0' : \
233 tolower(_c) + 10 - 'a'; \
234 })
235
236
237#define LINE_LENGTH 800
238#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
239 (n) * sizeof(struct partition)))
240#define sector(s) ((s) & 0x3f)
241#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
242
243#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
244 ((h) + heads * cylinder(s,c)))
245#define set_hsc(h,s,c,sector) { \
246 s = sector % sectors + 1; \
247 sector /= sectors; \
248 h = sector % heads; \
249 sector /= heads; \
250 c = sector & 0xff; \
251 s |= (sector >> 2) & 0xc0; \
252 }
253
254
255static unsigned int get_start_sect(const struct partition *p);
256static unsigned int get_nr_sects(const struct partition *p);
257
258/*
259 * per partition table entry data
260 *
261 * The four primary partitions have the same sectorbuffer (MBRbuffer)
262 * and have NULL ext_pointer.
263 * Each logical partition table entry has two pointers, one for the
264 * partition and one link to the next one.
265 */
266static struct pte {
267 struct partition *part_table; /* points into sectorbuffer */
268 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000269#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000270 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000271#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000272 uint offset; /* disk sector number */
273 char *sectorbuffer; /* disk sector contents */
274} ptes[MAXIMUM_PARTS];
275
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000276
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000277#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000278static void
279set_all_unchanged(void) {
280 int i;
281
282 for (i = 0; i < MAXIMUM_PARTS; i++)
283 ptes[i].changed = 0;
284}
285
286static void
287set_changed(int i) {
288 ptes[i].changed = 1;
289}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000290#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000291
292#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
293static struct partition *
294get_part_table(int i) {
295 return ptes[i].part_table;
296}
297#endif
298
299static const char *
300str_units(int n) { /* n==1: use singular */
301 if (n == 1)
302 return display_in_cyl_units ? _("cylinder") : _("sector");
303 else
304 return display_in_cyl_units ? _("cylinders") : _("sectors");
305}
306
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000307static int
308valid_part_table_flag(const unsigned char *b) {
309 return (b[510] == 0x55 && b[511] == 0xaa);
310}
311
312#ifdef CONFIG_FEATURE_FDISK_WRITABLE
313static char line_buffer[LINE_LENGTH];
314
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000315/* read line; return 0 or first char */
316static int
317read_line(void)
318{
319 static int got_eof = 0;
320
321 fflush (stdout); /* requested by niles@scyld.com */
322 line_ptr = line_buffer;
323 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
324 if (feof(stdin))
325 got_eof++; /* user typed ^D ? */
326 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000327 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
328 exit(1);
329 }
330 return 0;
331 }
332 while (*line_ptr && !isgraph(*line_ptr))
333 line_ptr++;
334 return *line_ptr;
335}
336
337static char
338read_char(const char *mesg)
339{
340 do {
341 fputs(mesg, stdout);
342 } while (!read_line());
343 return *line_ptr;
344}
345
346static char
347read_chars(const char *mesg)
348{
349 fputs(mesg, stdout);
350 if (!read_line()) {
351 *line_ptr = '\n';
352 line_ptr[1] = 0;
353 }
354 return *line_ptr;
355}
356
357static int
358read_hex(const struct systypes *sys)
359{
360 int hex;
361
362 while (1)
363 {
364 read_char(_("Hex code (type L to list codes): "));
365 if (*line_ptr == 'l' || *line_ptr == 'L')
366 list_types(sys);
367 else if (isxdigit (*line_ptr))
368 {
369 hex = 0;
370 do
371 hex = hex << 4 | hex_val(*line_ptr++);
372 while (isxdigit(*line_ptr));
373 return hex;
374 }
375 }
376}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000377#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000378
379#ifdef CONFIG_FEATURE_AIX_LABEL
380/*
381 * Copyright (C) Andreas Neuper, Sep 1998.
382 * This file may be redistributed under
383 * the terms of the GNU Public License.
384 */
385
386typedef struct {
387 unsigned int magic; /* expect AIX_LABEL_MAGIC */
388 unsigned int fillbytes1[124];
389 unsigned int physical_volume_id;
390 unsigned int fillbytes2[124];
391} aix_partition;
392
393#define AIX_LABEL_MAGIC 0xc9c2d4c1
394#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
395#define AIX_INFO_MAGIC 0x00072959
396#define AIX_INFO_MAGIC_SWAPPED 0x59290700
397
398#define aixlabel ((aix_partition *)MBRbuffer)
399
400
401/*
402 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000403 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
404 * Internationalization
405 *
406 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
407 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000408*/
409
410static int aix_other_endian;
411static short aix_volumes=1;
412
413/*
414 * only dealing with free blocks here
415 */
416
417static void
418aix_info( void ) {
419 puts(
420 _("\n\tThere is a valid AIX label on this disk.\n"
421 "\tUnfortunately Linux cannot handle these\n"
422 "\tdisks at the moment. Nevertheless some\n"
423 "\tadvice:\n"
424 "\t1. fdisk will destroy its contents on write.\n"
425 "\t2. Be sure that this disk is NOT a still vital\n"
426 "\t part of a volume group. (Otherwise you may\n"
427 "\t erase the other disks as well, if unmirrored.)\n"
428 "\t3. Before deleting this physical volume be sure\n"
429 "\t to remove the disk logically from your AIX\n"
430 "\t machine. (Otherwise you become an AIXpert).")
431 );
432}
433
434static void
435aix_nolabel( void )
436{
437 aixlabel->magic = 0;
438 aix_label = 0;
439 partitions = 4;
440 memset( MBRbuffer, 0, sizeof(MBRbuffer) ); /* avoid fdisk cores */
441 return;
442}
443
444static int
445check_aix_label( void )
446{
447 if (aixlabel->magic != AIX_LABEL_MAGIC &&
448 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
449 aix_label = 0;
450 aix_other_endian = 0;
451 return 0;
452 }
453 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
454 update_units();
455 aix_label = 1;
456 partitions= 1016;
457 aix_volumes = 15;
458 aix_info();
459 aix_nolabel(); /* %% */
460 aix_label = 1; /* %% */
461 return 1;
462}
463#endif /* AIX_LABEL */
464
465#ifdef CONFIG_FEATURE_OSF_LABEL
466/*
467 * Copyright (c) 1987, 1988 Regents of the University of California.
468 * All rights reserved.
469 *
470 * Redistribution and use in source and binary forms, with or without
471 * modification, are permitted provided that the following conditions
472 * are met:
473 * 1. Redistributions of source code must retain the above copyright
474 * notice, this list of conditions and the following disclaimer.
475 * 2. Redistributions in binary form must reproduce the above copyright
476 * notice, this list of conditions and the following disclaimer in the
477 * documentation and/or other materials provided with the distribution.
478 * 3. All advertising materials mentioning features or use of this software
479 * must display the following acknowledgement:
480 * This product includes software developed by the University of
481 * California, Berkeley and its contributors.
482 * 4. Neither the name of the University nor the names of its contributors
483 * may be used to endorse or promote products derived from this software
484 * without specific prior written permission.
485 *
486 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
487 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
488 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
489 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
490 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
491 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
492 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
493 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
494 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
495 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
496 * SUCH DAMAGE.
497 */
498
499
500#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000501#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000502#endif
503
504#ifndef BSD_MAXPARTITIONS
505#define BSD_MAXPARTITIONS 16
506#endif
507
508#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
509
510#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
511#define BSD_LABELSECTOR 1
512#define BSD_LABELOFFSET 0
513#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
514#define BSD_LABELSECTOR 0
515#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000516#elif defined (__s390__) || defined (__s390x__)
517#define BSD_LABELSECTOR 1
518#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000519#else
520#error unknown architecture
521#endif
522
523#define BSD_BBSIZE 8192 /* size of boot area, with label */
524#define BSD_SBSIZE 8192 /* max size of fs superblock */
525
526struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000527 uint32_t d_magic; /* the magic number */
528 int16_t d_type; /* drive type */
529 int16_t d_subtype; /* controller/d_type specific */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000530 char d_typename[16]; /* type name, e.g. "eagle" */
531 char d_packname[16]; /* pack identifier */
532 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000533 uint32_t d_secsize; /* # of bytes per sector */
534 uint32_t d_nsectors; /* # of data sectors per track */
535 uint32_t d_ntracks; /* # of tracks per cylinder */
536 uint32_t d_ncylinders; /* # of data cylinders per unit */
537 uint32_t d_secpercyl; /* # of data sectors per cylinder */
538 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000539 /*
540 * Spares (bad sector replacements) below
541 * are not counted in d_nsectors or d_secpercyl.
542 * Spare sectors are assumed to be physical sectors
543 * which occupy space at the end of each track and/or cylinder.
544 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000545 uint16_t d_sparespertrack; /* # of spare sectors per track */
546 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000547 /*
548 * Alternate cylinders include maintenance, replacement,
549 * configuration description areas, etc.
550 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000551 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000552
553 /* hardware characteristics: */
554 /*
555 * d_interleave, d_trackskew and d_cylskew describe perturbations
556 * in the media format used to compensate for a slow controller.
557 * Interleave is physical sector interleave, set up by the formatter
558 * or controller when formatting. When interleaving is in use,
559 * logically adjacent sectors are not physically contiguous,
560 * but instead are separated by some number of sectors.
561 * It is specified as the ratio of physical sectors traversed
562 * per logical sector. Thus an interleave of 1:1 implies contiguous
563 * layout, while 2:1 implies that logical sector 0 is separated
564 * by one sector from logical sector 1.
565 * d_trackskew is the offset of sector 0 on track N
566 * relative to sector 0 on track N-1 on the same cylinder.
567 * Finally, d_cylskew is the offset of sector 0 on cylinder N
568 * relative to sector 0 on cylinder N-1.
569 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000570 uint16_t d_rpm; /* rotational speed */
571 uint16_t d_interleave; /* hardware sector interleave */
572 uint16_t d_trackskew; /* sector 0 skew, per track */
573 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
574 uint32_t d_headswitch; /* head switch time, usec */
575 uint32_t d_trkseek; /* track-to-track seek, usec */
576 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000577#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000578 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000579#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000580 uint32_t d_spare[NSPARE]; /* reserved for future use */
581 uint32_t d_magic2; /* the magic number (again) */
582 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000583 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000584 uint16_t d_npartitions; /* number of partitions in following */
585 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
586 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000587 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000588 uint32_t p_size; /* number of sectors in partition */
589 uint32_t p_offset; /* starting sector */
590 uint32_t p_fsize; /* filesystem basic fragment size */
591 uint8_t p_fstype; /* filesystem type, see below */
592 uint8_t p_frag; /* filesystem fragments per block */
593 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000594 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
595};
596
597/* d_type values: */
598#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
599#define BSD_DTYPE_MSCP 2 /* MSCP */
600#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
601#define BSD_DTYPE_SCSI 4 /* SCSI */
602#define BSD_DTYPE_ESDI 5 /* ESDI interface */
603#define BSD_DTYPE_ST506 6 /* ST506 etc. */
604#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
605#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
606#define BSD_DTYPE_FLOPPY 10 /* floppy */
607
608/* d_subtype values: */
609#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
610#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
611#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
612
613#ifdef DKTYPENAMES
614static const char * const xbsd_dktypenames[] = {
615 "unknown",
616 "SMD",
617 "MSCP",
618 "old DEC",
619 "SCSI",
620 "ESDI",
621 "ST506",
622 "HP-IB",
623 "HP-FL",
624 "type 9",
625 "floppy",
626 0
627};
628#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
629#endif
630
631/*
632 * Filesystem type and version.
633 * Used to interpret other filesystem-specific
634 * per-partition information.
635 */
636#define BSD_FS_UNUSED 0 /* unused */
637#define BSD_FS_SWAP 1 /* swap */
638#define BSD_FS_V6 2 /* Sixth Edition */
639#define BSD_FS_V7 3 /* Seventh Edition */
640#define BSD_FS_SYSV 4 /* System V */
641#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
642#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
643#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
644#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
645#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
646#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
647#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
648#define BSD_FS_ISOFS BSD_FS_ISO9660
649#define BSD_FS_BOOT 13 /* partition contains bootstrap */
650#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
651#define BSD_FS_HFS 15 /* Macintosh HFS */
652#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
653
654/* this is annoying, but it's also the way it is :-( */
655#ifdef __alpha__
656#define BSD_FS_EXT2 8 /* ext2 file system */
657#else
658#define BSD_FS_MSDOS 8 /* MS-DOS file system */
659#endif
660
661#ifdef DKTYPENAMES
662static const struct systypes xbsd_fstypes[] = {
663/* BSD_FS_UNUSED */ {"\x00" "unused"},
664/* BSD_FS_SWAP */ {"\x01" "swap"},
665/* BSD_FS_V6 */ {"\x02" "Version 6"},
666/* BSD_FS_V7 */ {"\x03" "Version 7"},
667/* BSD_FS_SYSV */ {"\x04" "System V"},
668/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
669/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
670/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
671#ifdef __alpha__
672/* BSD_FS_EXT2 */ {"\x08" "ext2"},
673#else
674/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
675#endif
676/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
677/* BSD_FS_OTHER */ {"\x0a" "unknown"},
678/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
679/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
680/* BSD_FS_BOOT */ {"\x0d" "boot"},
681/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
682/* BSD_FS_HFS */ {"\x0f" "HFS"},
683/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
684 { NULL }
685};
686#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
687
688#endif
689
690/*
691 * flags shared by various drives:
692 */
693#define BSD_D_REMOVABLE 0x01 /* removable media */
694#define BSD_D_ECC 0x02 /* supports ECC */
695#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
696#define BSD_D_RAMDISK 0x08 /* disk emulator */
697#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
698#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
699
700#endif /* OSF_LABEL */
701
702/*
703 * Copyright (C) Andreas Neuper, Sep 1998.
704 * This file may be modified and redistributed under
705 * the terms of the GNU Public License.
706 */
707
708struct device_parameter { /* 48 bytes */
709 unsigned char skew;
710 unsigned char gap1;
711 unsigned char gap2;
712 unsigned char sparecyl;
713 unsigned short pcylcount;
714 unsigned short head_vol0;
715 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
716 unsigned char cmd_tag_queue_depth;
717 unsigned char unused0;
718 unsigned short unused1;
719 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
720 unsigned short bytes;
721 unsigned short ilfact;
722 unsigned int flags; /* controller flags */
723 unsigned int datarate;
724 unsigned int retries_on_error;
725 unsigned int ms_per_word;
726 unsigned short xylogics_gap1;
727 unsigned short xylogics_syncdelay;
728 unsigned short xylogics_readdelay;
729 unsigned short xylogics_gap2;
730 unsigned short xylogics_readgate;
731 unsigned short xylogics_writecont;
732};
733
734#define SGI_VOLHDR 0x00
735/* 1 and 2 were used for drive types no longer supported by SGI */
736#define SGI_SWAP 0x03
737/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
738#define SGI_VOLUME 0x06
739#define SGI_EFS 0x07
740#define SGI_LVOL 0x08
741#define SGI_RLVOL 0x09
742#define SGI_XFS 0x0a
743#define SGI_XFSLOG 0x0b
744#define SGI_XLV 0x0c
745#define SGI_XVM 0x0d
746#define ENTIRE_DISK SGI_VOLUME
747/*
748 * controller flags
749 */
750#define SECTOR_SLIP 0x01
751#define SECTOR_FWD 0x02
752#define TRACK_FWD 0x04
753#define TRACK_MULTIVOL 0x08
754#define IGNORE_ERRORS 0x10
755#define RESEEK 0x20
756#define ENABLE_CMDTAGQ 0x40
757
758typedef struct {
759 unsigned int magic; /* expect SGI_LABEL_MAGIC */
760 unsigned short boot_part; /* active boot partition */
761 unsigned short swap_part; /* active swap partition */
762 unsigned char boot_file[16]; /* name of the bootfile */
763 struct device_parameter devparam; /* 1 * 48 bytes */
764 struct volume_directory { /* 15 * 16 bytes */
765 unsigned char vol_file_name[8]; /* a character array */
766 unsigned int vol_file_start; /* number of logical block */
767 unsigned int vol_file_size; /* number of bytes */
768 } directory[15];
769 struct sgi_partition { /* 16 * 12 bytes */
770 unsigned int num_sectors; /* number of blocks */
771 unsigned int start_sector; /* must be cylinder aligned */
772 unsigned int id;
773 } partitions[16];
774 unsigned int csum;
775 unsigned int fillbytes;
776} sgi_partition;
777
778typedef struct {
779 unsigned int magic; /* looks like a magic number */
780 unsigned int a2;
781 unsigned int a3;
782 unsigned int a4;
783 unsigned int b1;
784 unsigned short b2;
785 unsigned short b3;
786 unsigned int c[16];
787 unsigned short d[3];
788 unsigned char scsi_string[50];
789 unsigned char serial[137];
790 unsigned short check1816;
791 unsigned char installer[225];
792} sgiinfo;
793
794#define SGI_LABEL_MAGIC 0x0be5a941
795#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
796#define SGI_INFO_MAGIC 0x00072959
797#define SGI_INFO_MAGIC_SWAPPED 0x59290700
798#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000799 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000800#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000801 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000802
803#define sgilabel ((sgi_partition *)MBRbuffer)
804#define sgiparam (sgilabel->devparam)
805
806typedef struct {
807 unsigned char info[128]; /* Informative text string */
808 unsigned char spare0[14];
809 struct sun_info {
810 unsigned char spare1;
811 unsigned char id;
812 unsigned char spare2;
813 unsigned char flags;
814 } infos[8];
815 unsigned char spare1[246]; /* Boot information etc. */
816 unsigned short rspeed; /* Disk rotational speed */
817 unsigned short pcylcount; /* Physical cylinder count */
818 unsigned short sparecyl; /* extra sects per cylinder */
819 unsigned char spare2[4]; /* More magic... */
820 unsigned short ilfact; /* Interleave factor */
821 unsigned short ncyl; /* Data cylinder count */
822 unsigned short nacyl; /* Alt. cylinder count */
823 unsigned short ntrks; /* Tracks per cylinder */
824 unsigned short nsect; /* Sectors per track */
825 unsigned char spare3[4]; /* Even more magic... */
826 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000827 uint32_t start_cylinder;
828 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000829 } partitions[8];
830 unsigned short magic; /* Magic number */
831 unsigned short csum; /* Label xor'd checksum */
832} sun_partition;
833
Eric Andersen040f4402003-07-30 08:40:37 +0000834
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000835#define SUN_LABEL_MAGIC 0xDABE
836#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
837#define sunlabel ((sun_partition *)MBRbuffer)
838#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000839 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000840#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000841 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +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__)
884/* We access this through a u_int64_t * when checksumming */
885static 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 Andersen341170b2003-07-14 19:03:14 +00001368 if (lseek (fd, (ext2_loff_t) 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 Andersen341170b2003-07-14 19:03:14 +00001536 if (lseek (fd, (ext2_loff_t) 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 Andersen341170b2003-07-14 19:03:14 +00001582 if (lseek (fd, (ext2_loff_t) 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 Andersen341170b2003-07-14 19:03:14 +00001587 if (lseek (fd, (ext2_loff_t) 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__)
1642typedef unsigned long long u_int64_t;
1643#endif
1644
1645static void
1646alpha_bootblock_checksum (char *boot)
1647{
1648 u_int64_t *dp, sum;
1649 int i;
1650
1651 dp = (u_int64_t *)boot;
1652 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) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001852 int i, w;
1853 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001854
Eric Andersen040f4402003-07-30 08:40:37 +00001855 w = strlen(disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001856
Eric Andersen040f4402003-07-30 08:40:37 +00001857 if(xtra) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001858 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1859 "%d cylinders, %d physical cylinders\n"
1860 "%d extra sects/cyl, interleave %d:1\n"
1861 "%s\n"
1862 "Units = %s of %d * 512 bytes\n\n"),
1863 disk_device, heads, sectors, cylinders,
1864 SGI_SSWAP16(sgiparam.pcylcount),
1865 SGI_SSWAP16(sgiparam.sparecyl),
1866 SGI_SSWAP16(sgiparam.ilfact),
1867 (char *)sgilabel,
1868 str_units(PLURAL), units_per_sector);
1869 } else {
1870 printf( _("\nDisk %s (SGI disk label): "
1871 "%d heads, %d sectors, %d cylinders\n"
1872 "Units = %s of %d * 512 bytes\n\n"),
1873 disk_device, heads, sectors, cylinders,
1874 str_units(PLURAL), units_per_sector );
1875 }
1876 printf(_("----- partitions -----\n"
1877 "Pt# %*s Info Start End Sectors Id System\n"),
1878 w + 1, _("Device"));
1879 for (i = 0 ; i < partitions; i++) {
1880 if( sgi_get_num_sectors(i) || debug ) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001881 uint32_t start = sgi_get_start_sector(i);
1882 uint32_t len = sgi_get_num_sectors(i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001883 kpi++; /* only count nonempty partitions */
1884 printf(
1885 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1886/* fdisk part number */ i+1,
1887/* device */ partname(disk_device, kpi, w+2),
1888/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1889/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1890/* start */ (long) scround(start),
1891/* end */ (long) scround(start+len)-1,
1892/* no odd flag on end */ (long) len,
1893/* type id */ sgi_get_sysid(i),
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001894/* type name */ partition_type(sgi_get_sysid(i)));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001895 }
1896 }
1897 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1898 "----- Directory Entries -----\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00001899 sgilabel->boot_file);
1900 for (i = 0 ; i < sgi_volumes; i++) {
1901 if (sgilabel->directory[i].vol_file_size) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001902 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1903 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001904 char*name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001905
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001906 printf(_("%2d: %-10s sector%5u size%8u\n"),
1907 i, name, (unsigned int) start, (unsigned int) len);
1908 }
1909 }
1910}
1911
1912static void
1913sgi_set_bootpartition( int i )
1914{
1915 sgilabel->boot_part = SGI_SSWAP16(((short)i));
1916}
1917
Eric Andersen040f4402003-07-30 08:40:37 +00001918static unsigned int
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001919sgi_get_lastblock(void) {
1920 return heads * sectors * cylinders;
1921}
1922
1923static void
1924sgi_set_swappartition( int i ) {
1925 sgilabel->swap_part = SGI_SSWAP16(((short)i));
1926}
1927
1928static int
Eric Andersen040f4402003-07-30 08:40:37 +00001929sgi_check_bootfile(const char* aFile) {
1930
1931 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1932 printf(_("\nInvalid Bootfile!\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001933 "\tThe bootfile must be an absolute non-zero pathname,\n"
Eric Andersen040f4402003-07-30 08:40:37 +00001934 "\te.g. \"/unix\" or \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001935 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001936 } else {
1937 if (strlen(aFile) > 16) {
1938 printf(_("\n\tName of Bootfile too long: "
1939 "16 bytes maximum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001940 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001941 } else {
1942 if (aFile[0] != '/') {
1943 printf(_("\n\tBootfile must have a "
1944 "fully qualified pathname.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001945 return 0;
1946 }
Eric Andersen040f4402003-07-30 08:40:37 +00001947 }
1948 }
1949 if (strncmp(aFile, sgilabel->boot_file, 16)) {
1950 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1951 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001952 /* filename is correct and did change */
1953 return 1;
1954 }
1955 return 0; /* filename did not change */
1956}
1957
1958static const char *
1959sgi_get_bootfile(void) {
1960 return sgilabel->boot_file;
1961}
1962
1963static void
Eric Andersen040f4402003-07-30 08:40:37 +00001964sgi_set_bootfile(const char* aFile) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001965 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001966
1967 if (sgi_check_bootfile(aFile)) {
1968 while (i < 16) {
1969 if ((aFile[i] != '\n') /* in principle caught again by next line */
1970 && (strlen(aFile) > i))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001971 sgilabel->boot_file[i] = aFile[i];
1972 else
1973 sgilabel->boot_file[i] = 0;
1974 i++;
1975 }
Eric Andersen040f4402003-07-30 08:40:37 +00001976 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001977 }
1978}
1979
1980static void
1981create_sgiinfo(void)
1982{
1983 /* I keep SGI's habit to write the sgilabel to the second block */
Eric Andersen040f4402003-07-30 08:40:37 +00001984 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1985 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1986 strncpy(sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001987}
1988
Eric Andersen040f4402003-07-30 08:40:37 +00001989static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001990
1991static void
Eric Andersen040f4402003-07-30 08:40:37 +00001992sgi_write_table(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001993 sgilabel->csum = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001994 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001995 (unsigned int*)sgilabel,
Eric Andersen040f4402003-07-30 08:40:37 +00001996 sizeof(*sgilabel)));
1997 assert(two_s_complement_32bit_sum(
1998 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
1999 if (lseek(fd, 0, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002000 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002001 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002002 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002003 if (! strncmp(sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002004 /*
Eric Andersen040f4402003-07-30 08:40:37 +00002005 * keep this habit of first writing the "sgilabel".
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002006 * I never tested whether it works without (AN 981002).
2007 */
Eric Andersen040f4402003-07-30 08:40:37 +00002008 sgiinfo *info = fill_sgiinfo();
2009 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2010 if (lseek(fd, (long long)infostartblock*
2011 SECTOR_SIZE, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002012 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002013 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002014 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002015 free(info);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002016 }
2017}
2018
2019static int
Eric Andersen040f4402003-07-30 08:40:37 +00002020compare_start(int *x, int *y) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002021 /*
2022 * sort according to start sectors
2023 * and prefers largest partition:
2024 * entry zero is entire disk entry
2025 */
Eric Andersen040f4402003-07-30 08:40:37 +00002026 unsigned int i = *x;
2027 unsigned int j = *y;
2028 unsigned int a = sgi_get_start_sector(i);
2029 unsigned int b = sgi_get_start_sector(j);
2030 unsigned int c = sgi_get_num_sectors(i);
2031 unsigned int d = sgi_get_num_sectors(j);
2032
2033 if (a == b)
2034 return (d > c) ? 1 : (d == c) ? 0 : -1;
2035 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002036}
2037
2038
2039static int
Eric Andersen040f4402003-07-30 08:40:37 +00002040verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002041{
2042 int Index[16]; /* list of valid partitions */
2043 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
Eric Andersen040f4402003-07-30 08:40:37 +00002044 int entire = 0, i = 0;
2045 unsigned int start = 0;
2046 long long gap = 0; /* count unused blocks */
2047 unsigned int lastblock = sgi_get_lastblock();
2048
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002049 clearfreelist();
Eric Andersen040f4402003-07-30 08:40:37 +00002050 for (i=0; i<16; i++) {
2051 if (sgi_get_num_sectors(i) != 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002052 Index[sortcount++]=i;
Eric Andersen040f4402003-07-30 08:40:37 +00002053 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2054 if (entire++ == 1) {
2055 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002056 printf(_("More than one entire disk entry present.\n"));
2057 }
2058 }
2059 }
2060 }
Eric Andersen040f4402003-07-30 08:40:37 +00002061 if (sortcount == 0) {
2062 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002063 printf(_("No partitions defined\n"));
Eric Andersen040f4402003-07-30 08:40:37 +00002064 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002065 }
Eric Andersen040f4402003-07-30 08:40:37 +00002066 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2067 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2068 if ((Index[0] != 10) && verbose)
2069 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2070 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2071 printf(_("The entire disk partition should start "
2072 "at block 0,\n"
2073 "not at diskblock %d.\n"),
2074 sgi_get_start_sector(Index[0]));
2075 if (debug) /* I do not understand how some disks fulfil it */
2076 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2077 printf(_("The entire disk partition is only %d diskblock large,\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002078 "but the disk is %d diskblocks long.\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00002079 sgi_get_num_sectors(Index[0]), lastblock);
2080 lastblock = sgi_get_num_sectors(Index[0]);
2081 } else {
2082 if (verbose)
2083 printf(_("One Partition (#11) should cover the entire disk.\n"));
2084 if (debug>2)
2085 printf("sysid=%d\tpartition=%d\n",
2086 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002087 }
Eric Andersen040f4402003-07-30 08:40:37 +00002088 for (i=1, start=0; i<sortcount; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002089 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
Eric Andersen040f4402003-07-30 08:40:37 +00002090
2091 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2092 if (debug) /* I do not understand how some disks fulfil it */
2093 if (verbose)
2094 printf(_("Partition %d does not start on cylinder boundary.\n"),
2095 Index[i]+1);
2096 }
2097 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2098 if (debug) /* I do not understand how some disks fulfil it */
2099 if (verbose)
2100 printf(_("Partition %d does not end on cylinder boundary.\n"),
2101 Index[i]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002102 }
2103 /* We cannot handle several "entire disk" entries. */
Eric Andersen040f4402003-07-30 08:40:37 +00002104 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2105 if (start > sgi_get_start_sector(Index[i])) {
2106 if (verbose)
2107 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002108 Index[i-1]+1, Index[i]+1,
Eric Andersen040f4402003-07-30 08:40:37 +00002109 start - sgi_get_start_sector(Index[i]));
2110 if (gap > 0) gap = -gap;
2111 if (gap == 0) gap = -1;
2112 }
2113 if (start < sgi_get_start_sector(Index[i])) {
2114 if (verbose)
2115 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2116 sgi_get_start_sector(Index[i]) - start,
2117 start, sgi_get_start_sector(Index[i])-1);
2118 gap += sgi_get_start_sector(Index[i]) - start;
2119 add2freelist(start, sgi_get_start_sector(Index[i]));
2120 }
2121 start = sgi_get_start_sector(Index[i])
2122 + sgi_get_num_sectors(Index[i]);
2123 if (debug > 1) {
2124 if (verbose)
2125 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002126 sgi_get_start_sector(Index[i]),
2127 sgi_get_num_sectors(Index[i]),
Eric Andersen040f4402003-07-30 08:40:37 +00002128 sgi_get_sysid(Index[i]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002129 }
2130 }
Eric Andersen040f4402003-07-30 08:40:37 +00002131 if (start < lastblock) {
2132 if (verbose)
2133 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2134 lastblock - start, start, lastblock-1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002135 gap += lastblock - start;
Eric Andersen040f4402003-07-30 08:40:37 +00002136 add2freelist(start, lastblock);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002137 }
2138 /*
2139 * Done with arithmetics
2140 * Go for details now
2141 */
Eric Andersen040f4402003-07-30 08:40:37 +00002142 if (verbose) {
2143 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2144 printf(_("\nThe boot partition does not exist.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002145 }
Eric Andersen040f4402003-07-30 08:40:37 +00002146 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2147 printf(_("\nThe swap partition does not exist.\n"));
2148 } else {
2149 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2150 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2151 printf(_("\nThe swap partition has no swap type.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002152 }
Eric Andersen040f4402003-07-30 08:40:37 +00002153 if (sgi_check_bootfile("/unix"))
2154 printf(_("\tYou have chosen an unusual boot file name.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002155 }
Eric Andersen040f4402003-07-30 08:40:37 +00002156 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002157}
2158
2159static int
2160sgi_gaps(void) {
2161 /*
2162 * returned value is:
2163 * = 0 : disk is properly filled to the rim
2164 * < 0 : there is an overlap
2165 * > 0 : there is still some vacant space
2166 */
2167 return verify_sgi(0);
2168}
2169
2170static void
2171sgi_change_sysid( int i, int sys )
2172{
2173 if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
2174 {
2175 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2176 return;
2177 }
2178 if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2179 && (sgi_get_start_sector(i)<1) )
2180 {
2181 read_chars(
2182 _("It is highly recommended that the partition at offset 0\n"
2183 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2184 "retrieve from its directory standalone tools like sash and fx.\n"
2185 "Only the \"SGI volume\" entire disk section may violate this.\n"
2186 "Type YES if you are sure about tagging this partition differently.\n"));
2187 if (strcmp (line_ptr, _("YES\n")))
2188 return;
2189 }
2190 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2191}
2192
2193/* returns partition index of first entry marked as entire disk */
2194static int
2195sgi_entire(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00002196 int i;
2197
2198 for(i=0; i<16; i++)
2199 if(sgi_get_sysid(i) == SGI_VOLUME)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002200 return i;
2201 return -1;
2202}
2203
2204static void
Eric Andersen040f4402003-07-30 08:40:37 +00002205sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
2206
2207 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2208 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2209 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002210 set_changed(i);
Eric Andersen040f4402003-07-30 08:40:37 +00002211 if (sgi_gaps() < 0) /* rebuild freelist */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002212 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2213}
2214
2215static void
2216sgi_set_entire(void) {
2217 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002218
2219 for(n=10; n < partitions; n++) {
2220 if(!sgi_get_num_sectors(n) ) {
2221 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002222 break;
2223 }
2224 }
2225}
2226
2227static void
2228sgi_set_volhdr(void)
2229{
2230 int n;
2231 for( n=8; n<partitions; n++ )
2232 {
2233 if(!sgi_get_num_sectors( n ) )
2234 {
2235 /*
2236 * 5 cylinders is an arbitrary value I like
2237 * IRIX 5.3 stored files in the volume header
2238 * (like sash, symmon, fx, ide) with ca. 3200
2239 * sectors.
2240 */
2241 if( heads * sectors * 5 < sgi_get_lastblock() )
2242 sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
2243 break;
2244 }
2245 }
2246}
2247
2248static void
2249sgi_delete_partition( int i )
2250{
2251 sgi_set_partition( i, 0, 0, 0 );
2252}
2253
2254static void
2255sgi_add_partition( int n, int sys )
2256{
2257 char mesg[256];
Eric Andersen040f4402003-07-30 08:40:37 +00002258 unsigned int first=0, last=0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002259
2260 if( n == 10 ) {
2261 sys = SGI_VOLUME;
2262 } else if ( n == 8 ) {
2263 sys = 0;
2264 }
Eric Andersen040f4402003-07-30 08:40:37 +00002265 if(sgi_get_num_sectors(n)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002266 printf(_("Partition %d is already defined. Delete "
2267 "it before re-adding it.\n"), n + 1);
2268 return;
2269 }
Eric Andersen040f4402003-07-30 08:40:37 +00002270 if( (sgi_entire() == -1) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002271 printf(_("Attempting to generate entire disk entry automatically.\n"));
2272 sgi_set_entire();
2273 sgi_set_volhdr();
2274 }
Eric Andersen040f4402003-07-30 08:40:37 +00002275 if( (sgi_gaps() == 0) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002276 printf(_("The entire disk is already covered with partitions.\n"));
2277 return;
2278 }
Eric Andersen040f4402003-07-30 08:40:37 +00002279 if(sgi_gaps() < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002280 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2281 return;
2282 }
2283 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2284 for(;;) {
2285 if(sys == SGI_VOLUME) {
2286 last = sgi_get_lastblock();
2287 first = read_int(0, 0, last-1, 0, mesg);
2288 if( first != 0 ) {
2289 printf(_("It is highly recommended that eleventh partition\n"
2290 "covers the entire disk and is of type `SGI volume'\n"));
2291 }
2292 } else {
2293 first = freelist[0].first;
2294 last = freelist[0].last;
2295 first = read_int(scround(first), scround(first), scround(last)-1,
2296 0, mesg);
2297 }
2298 if (display_in_cyl_units)
2299 first *= units_per_sector;
2300 else
2301 first = first; /* align to cylinder if you know how ... */
2302 if( !last )
2303 last = isinfreelist(first);
2304 if( last == 0 ) {
2305 printf(_("You will get a partition overlap on the disk. "
2306 "Fix it first!\n"));
2307 } else
2308 break;
2309 }
2310 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2311 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2312 scround(first), mesg)+1;
2313 if (display_in_cyl_units)
2314 last *= units_per_sector;
2315 else
2316 last = last; /* align to cylinder if You know how ... */
2317 if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
2318 printf(_("It is highly recommended that eleventh partition\n"
2319 "covers the entire disk and is of type `SGI volume'\n"));
2320 sgi_set_partition( n, first, last-first, sys );
2321}
2322
Eric Andersen040f4402003-07-30 08:40:37 +00002323#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002324static void
2325create_sgilabel(void)
2326{
2327 struct hd_geometry geometry;
Eric Andersen040f4402003-07-30 08:40:37 +00002328 struct {
2329 unsigned int start;
2330 unsigned int nsect;
2331 int sysid;
2332 } old[4];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002333 int i=0;
Eric Andersen040f4402003-07-30 08:40:37 +00002334 long longsectors; /* the number of sectors on the device */
2335 int res; /* the result from the ioctl */
2336 int sec_fac; /* the sector factor */
2337
2338 sec_fac = sector_size / 512; /* determine the sector factor */
2339
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002340 fprintf( stderr,
2341 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2342 "until you decide to write them. After that, of course, the previous\n"
2343 "content will be unrecoverably lost.\n\n"));
2344
2345 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
Eric Andersen040f4402003-07-30 08:40:37 +00002346 res = ioctl(fd, BLKGETSIZE, &longsectors);
2347 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002348 heads = geometry.heads;
2349 sectors = geometry.sectors;
Eric Andersen040f4402003-07-30 08:40:37 +00002350 if (res == 0) {
2351 /* the get device size ioctl was successful */
2352 cylinders = longsectors / (heads * sectors);
2353 cylinders /= sec_fac;
2354 } else {
2355 /* otherwise print error and use truncated version */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002356 cylinders = geometry.cylinders;
Eric Andersen040f4402003-07-30 08:40:37 +00002357 fprintf(stderr,
2358 _("Warning: BLKGETSIZE ioctl failed on %s. "
2359 "Using geometry cylinder value of %d.\n"
2360 "This value may be truncated for devices"
2361 " > 33.8 GB.\n"), disk_device, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002362 }
Eric Andersen040f4402003-07-30 08:40:37 +00002363 }
2364 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002365 old[i].sysid = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002366 if(valid_part_table_flag(MBRbuffer)) {
2367 if(get_part_table(i)->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002368 old[i].sysid = get_part_table(i)->sys_ind;
Eric Andersen040f4402003-07-30 08:40:37 +00002369 old[i].start = get_start_sect(get_part_table(i));
2370 old[i].nsect = get_nr_sects(get_part_table(i));
2371 printf(_("Trying to keep parameters of partition %d.\n"), i);
2372 if (debug)
2373 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2374 old[i].sysid, old[i].start, old[i].nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002375 }
2376 }
2377 }
Eric Andersen040f4402003-07-30 08:40:37 +00002378
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002379 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2380 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2381 sgilabel->boot_part = SGI_SSWAP16(0);
2382 sgilabel->swap_part = SGI_SSWAP16(1);
2383
2384 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2385 memset(sgilabel->boot_file, 0, 16);
2386 strcpy(sgilabel->boot_file, "/unix");
2387
2388 sgilabel->devparam.skew = (0);
2389 sgilabel->devparam.gap1 = (0);
2390 sgilabel->devparam.gap2 = (0);
2391 sgilabel->devparam.sparecyl = (0);
2392 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2393 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2394 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
2395 /* tracks/cylinder (heads) */
2396 sgilabel->devparam.cmd_tag_queue_depth = (0);
2397 sgilabel->devparam.unused0 = (0);
2398 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2399 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
2400 /* sectors/track */
2401 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2402 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2403 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
2404 IGNORE_ERRORS|RESEEK);
2405 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2406 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2407 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2408 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2409 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2410 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2411 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2412 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2413 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2414 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2415 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2416 sgi_label = 1;
2417 partitions = 16;
2418 sgi_volumes = 15;
2419 sgi_set_entire();
2420 sgi_set_volhdr();
Eric Andersen040f4402003-07-30 08:40:37 +00002421 for (i = 0; i < 4; i++) {
2422 if(old[i].sysid) {
2423 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002424 }
2425 }
2426}
2427
2428static void
2429sgi_set_xcyl(void)
2430{
2431 /* do nothing in the beginning */
2432}
Eric Andersen040f4402003-07-30 08:40:37 +00002433#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002434
2435/* _____________________________________________________________
2436 */
2437
Eric Andersen040f4402003-07-30 08:40:37 +00002438static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002439fill_sgiinfo(void)
2440{
Eric Andersen040f4402003-07-30 08:40:37 +00002441 sgiinfo *info = calloc(1, sizeof(sgiinfo));
2442
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002443 info->magic=SGI_SSWAP32(SGI_INFO_MAGIC);
2444 info->b1=SGI_SSWAP32(-1);
2445 info->b2=SGI_SSWAP16(-1);
2446 info->b3=SGI_SSWAP16(1);
2447 /* You may want to replace this string !!!!!!! */
2448 strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" );
2449 strcpy( info->serial, "0000" );
2450 info->check1816 = SGI_SSWAP16(18*256 +16 );
2451 strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
2452 return info;
2453}
2454#endif /* SGI_LABEL */
2455
2456
2457#ifdef CONFIG_FEATURE_SUN_LABEL
2458/*
2459 * fdisksunlabel.c
2460 *
2461 * I think this is mostly, or entirely, due to
2462 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2463 *
2464 * Merged with fdisk for other architectures, aeb, June 1998.
2465 *
2466 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2467 * Internationalization
2468 */
2469
2470
2471static int sun_other_endian;
2472static int scsi_disk;
2473static int floppy;
2474
2475#ifndef IDE0_MAJOR
2476#define IDE0_MAJOR 3
2477#endif
2478#ifndef IDE1_MAJOR
2479#define IDE1_MAJOR 22
2480#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002481
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002482static void guess_device_type(void) {
2483 struct stat bootstat;
2484
2485 if (fstat (fd, &bootstat) < 0) {
2486 scsi_disk = 0;
2487 floppy = 0;
2488 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002489 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2490 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002491 scsi_disk = 0;
2492 floppy = 0;
2493 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002494 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002495 scsi_disk = 0;
2496 floppy = 1;
2497 } else {
2498 scsi_disk = 1;
2499 floppy = 0;
2500 }
2501}
2502
2503static const struct systypes sun_sys_types[] = {
2504/* 0 */ {"\x00" "Empty" },
2505/* 1 */ {"\x01" "Boot" },
2506/* 2 */ {"\x02" "SunOS root" },
2507/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
2508/* 4 */ {"\x04" "SunOS usr" },
2509/* WHOLE_DISK */ {"\x05" "Whole disk" },
2510/* 6 */ {"\x06" "SunOS stand" },
2511/* 7 */ {"\x07" "SunOS var" },
2512/* 8 */ {"\x08" "SunOS home" },
2513/* LINUX_SWAP */ {"\x82" "Linux swap" },
2514/* LINUX_NATIVE */ {"\x83" "Linux native" },
2515/* 0x8e */ {"\x8e" "Linux LVM" },
2516/* New (2.2.x) raid partition with autodetect using persistent superblock */
2517/* 0xfd */ {"\xfd" "Linux raid autodetect" },
2518 { NULL }
2519};
2520
2521
2522static void
2523set_sun_partition(int i, uint start, uint stop, int sysid) {
2524 sunlabel->infos[i].id = sysid;
2525 sunlabel->partitions[i].start_cylinder =
2526 SUN_SSWAP32(start / (heads * sectors));
2527 sunlabel->partitions[i].num_sectors =
2528 SUN_SSWAP32(stop - start);
2529 set_changed(i);
2530}
2531
2532static void
2533sun_nolabel(void) {
2534 sun_label = 0;
2535 sunlabel->magic = 0;
2536 partitions = 4;
2537}
2538
2539static int
2540check_sun_label(void) {
2541 unsigned short *ush;
2542 int csum;
2543
2544 if (sunlabel->magic != SUN_LABEL_MAGIC &&
2545 sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2546 sun_label = 0;
2547 sun_other_endian = 0;
2548 return 0;
2549 }
2550 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2551 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2552 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2553 if (csum) {
2554 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2555 "Probably you'll have to set all the values,\n"
2556 "e.g. heads, sectors, cylinders and partitions\n"
2557 "or force a fresh label (s command in main menu)\n"));
2558 } else {
2559 heads = SUN_SSWAP16(sunlabel->ntrks);
2560 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2561 sectors = SUN_SSWAP16(sunlabel->nsect);
2562 }
2563 update_units();
2564 sun_label = 1;
2565 partitions = 8;
2566 return 1;
2567}
2568
2569static const struct sun_predefined_drives {
2570 const char *vendor;
2571 const char *model;
2572 unsigned short sparecyl;
2573 unsigned short ncyl;
2574 unsigned short nacyl;
2575 unsigned short pcylcount;
2576 unsigned short ntrks;
2577 unsigned short nsect;
2578 unsigned short rspeed;
2579} sun_drives[] = {
2580{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2581{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2582{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2583{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2584{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2585{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2586{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2587{"","SUN0104",1,974,2,1019,6,35,3662},
2588{"","SUN0207",4,1254,2,1272,9,36,3600},
2589{"","SUN0327",3,1545,2,1549,9,46,3600},
2590{"","SUN0340",0,1538,2,1544,6,72,4200},
2591{"","SUN0424",2,1151,2,2500,9,80,4400},
2592{"","SUN0535",0,1866,2,2500,7,80,5400},
2593{"","SUN0669",5,1614,2,1632,15,54,3600},
2594{"","SUN1.0G",5,1703,2,1931,15,80,3597},
2595{"","SUN1.05",0,2036,2,2038,14,72,5400},
2596{"","SUN1.3G",6,1965,2,3500,17,80,5400},
2597{"","SUN2.1G",0,2733,2,3500,19,80,5400},
2598{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2599};
2600
2601static const struct sun_predefined_drives *
2602sun_autoconfigure_scsi(void) {
2603 const struct sun_predefined_drives *p = NULL;
2604
2605#ifdef SCSI_IOCTL_GET_IDLUN
2606 unsigned int id[2];
2607 char buffer[2048];
2608 char buffer2[2048];
2609 FILE *pfd;
2610 char *vendor;
2611 char *model;
2612 char *q;
2613 int i;
2614
2615 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2616 sprintf(buffer,
2617 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2618#if 0
2619 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2620#else
2621 /* This is very wrong (works only if you have one HBA),
2622 but I haven't found a way how to get hostno
2623 from the current kernel */
2624 0,
2625#endif
2626 (id[0]>>16)&0xff,
2627 id[0]&0xff,
2628 (id[0]>>8)&0xff);
2629 pfd = fopen("/proc/scsi/scsi","r");
2630 if (pfd) {
2631 while (fgets(buffer2,2048,pfd)) {
2632 if (!strcmp(buffer, buffer2)) {
2633 if (fgets(buffer2,2048,pfd)) {
2634 q = strstr(buffer2,"Vendor: ");
2635 if (q) {
2636 q += 8;
2637 vendor = q;
2638 q = strstr(q," ");
2639 *q++ = 0; /* truncate vendor name */
2640 q = strstr(q,"Model: ");
2641 if (q) {
2642 *q = 0;
2643 q += 7;
2644 model = q;
2645 q = strstr(q," Rev: ");
2646 if (q) {
2647 *q = 0;
2648 for (i = 0; i < SIZE(sun_drives); i++) {
2649 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2650 continue;
2651 if (!strstr(model, sun_drives[i].model))
2652 continue;
2653 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2654 p = sun_drives + i;
2655 break;
2656 }
2657 }
2658 }
2659 }
2660 }
2661 break;
2662 }
2663 }
2664 fclose(pfd);
2665 }
2666 }
2667#endif
2668 return p;
2669}
2670
2671static void create_sunlabel(void)
2672{
2673 struct hd_geometry geometry;
2674 unsigned int ndiv;
2675 int i;
2676 unsigned char c;
2677 const struct sun_predefined_drives *p = NULL;
2678
2679 fprintf(stderr,
2680 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2681 "until you decide to write them. After that, of course, the previous\n"
2682 "content won't be recoverable.\n\n"));
2683#if BYTE_ORDER == LITTLE_ENDIAN
2684 sun_other_endian = 1;
2685#else
2686 sun_other_endian = 0;
2687#endif
2688 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2689 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2690 if (!floppy) {
2691 puts(_("Drive type\n"
2692 " ? auto configure\n"
2693 " 0 custom (with hardware detected defaults)"));
2694 for (i = 0; i < SIZE(sun_drives); i++) {
2695 printf(" %c %s%s%s\n",
2696 i + 'a', sun_drives[i].vendor,
2697 (*sun_drives[i].vendor) ? " " : "",
2698 sun_drives[i].model);
2699 }
2700 for (;;) {
2701 c = read_char(_("Select type (? for auto, 0 for custom): "));
2702 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2703 p = sun_drives + c - 'a';
2704 break;
2705 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2706 p = sun_drives + c - 'A';
2707 break;
2708 } else if (c == '0') {
2709 break;
2710 } else if (c == '?' && scsi_disk) {
2711 p = sun_autoconfigure_scsi();
2712 if (!p)
2713 printf(_("Autoconfigure failed.\n"));
2714 else
2715 break;
2716 }
2717 }
2718 }
2719 if (!p || floppy) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002720 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002721 heads = geometry.heads;
2722 sectors = geometry.sectors;
2723 cylinders = geometry.cylinders;
2724 } else {
2725 heads = 0;
2726 sectors = 0;
2727 cylinders = 0;
2728 }
2729 if (floppy) {
2730 sunlabel->nacyl = 0;
2731 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2732 sunlabel->rspeed = SUN_SSWAP16(300);
2733 sunlabel->ilfact = SUN_SSWAP16(1);
2734 sunlabel->sparecyl = 0;
2735 } else {
2736 heads = read_int(1,heads,1024,0,_("Heads"));
2737 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2738 if (cylinders)
2739 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2740 else
2741 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2742 sunlabel->nacyl =
2743 SUN_SSWAP16(read_int(0,2,65535,0,
2744 _("Alternate cylinders")));
2745 sunlabel->pcylcount =
2746 SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl),
2747 65535,0,_("Physical cylinders")));
2748 sunlabel->rspeed =
2749 SUN_SSWAP16(read_int(1,5400,100000,0,
2750 _("Rotation speed (rpm)")));
2751 sunlabel->ilfact =
2752 SUN_SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
2753 sunlabel->sparecyl =
2754 SUN_SSWAP16(read_int(0,0,sectors,0,
2755 _("Extra sectors per cylinder")));
2756 }
2757 } else {
2758 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2759 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2760 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2761 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2762 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2763 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2764 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2765 sunlabel->ilfact = SUN_SSWAP16(1);
2766 cylinders = p->ncyl;
2767 heads = p->ntrks;
2768 sectors = p->nsect;
2769 puts(_("You may change all the disk params from the x menu"));
2770 }
2771
2772 snprintf(sunlabel->info, sizeof(sunlabel->info),
2773 "%s%s%s cyl %d alt %d hd %d sec %d",
2774 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2775 p ? p->model
2776 : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2777 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2778
2779 sunlabel->ntrks = SUN_SSWAP16(heads);
2780 sunlabel->nsect = SUN_SSWAP16(sectors);
2781 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2782 if (floppy)
2783 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2784 else {
2785 if (cylinders * heads * sectors >= 150 * 2048) {
2786 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2787 } else
2788 ndiv = cylinders * 2 / 3;
2789 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2790 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2791 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2792 }
2793 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2794 {
2795 unsigned short *ush = (unsigned short *)sunlabel;
2796 unsigned short csum = 0;
2797 while(ush < (unsigned short *)(&sunlabel->csum))
2798 csum ^= *ush++;
2799 sunlabel->csum = csum;
2800 }
2801
2802 set_all_unchanged();
2803 set_changed(0);
2804 get_boot(create_empty_sun);
2805}
2806
2807static void
2808toggle_sunflags(int i, unsigned char mask) {
2809 if (sunlabel->infos[i].flags & mask)
2810 sunlabel->infos[i].flags &= ~mask;
2811 else sunlabel->infos[i].flags |= mask;
2812 set_changed(i);
2813}
2814
2815static void
2816fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) {
2817 int i, continuous = 1;
2818 *start = 0; *stop = cylinders * heads * sectors;
2819 for (i = 0; i < partitions; i++) {
2820 if (sunlabel->partitions[i].num_sectors
2821 && sunlabel->infos[i].id
2822 && sunlabel->infos[i].id != WHOLE_DISK) {
2823 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2824 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2825 if (continuous) {
2826 if (starts[i] == *start)
2827 *start += lens[i];
2828 else if (starts[i] + lens[i] >= *stop)
2829 *stop = starts[i];
2830 else
2831 continuous = 0;
2832 /* There will be probably more gaps
2833 than one, so lets check afterwards */
2834 }
2835 } else {
2836 starts[i] = 0;
2837 lens[i] = 0;
2838 }
2839 }
2840}
2841
2842static uint *verify_sun_starts;
2843
2844static int
2845verify_sun_cmp(int *a, int *b) {
2846 if (*a == -1) return 1;
2847 if (*b == -1) return -1;
2848 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2849 return -1;
2850}
2851
2852static void
2853verify_sun(void) {
2854 uint starts[8], lens[8], start, stop;
2855 int i,j,k,starto,endo;
2856 int array[8];
2857
2858 verify_sun_starts = starts;
2859 fetch_sun(starts,lens,&start,&stop);
2860 for (k = 0; k < 7; k++) {
2861 for (i = 0; i < 8; i++) {
2862 if (k && (lens[i] % (heads * sectors))) {
2863 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2864 }
2865 if (lens[i]) {
2866 for (j = 0; j < i; j++)
2867 if (lens[j]) {
2868 if (starts[j] == starts[i]+lens[i]) {
2869 starts[j] = starts[i]; lens[j] += lens[i];
2870 lens[i] = 0;
2871 } else if (starts[i] == starts[j]+lens[j]){
2872 lens[j] += lens[i];
2873 lens[i] = 0;
2874 } else if (!k) {
2875 if (starts[i] < starts[j]+lens[j] &&
2876 starts[j] < starts[i]+lens[i]) {
2877 starto = starts[i];
2878 if (starts[j] > starto)
2879 starto = starts[j];
2880 endo = starts[i]+lens[i];
2881 if (starts[j]+lens[j] < endo)
2882 endo = starts[j]+lens[j];
2883 printf(_("Partition %d overlaps with others in "
2884 "sectors %d-%d\n"), i+1, starto, endo);
2885 }
2886 }
2887 }
2888 }
2889 }
2890 }
2891 for (i = 0; i < 8; i++) {
2892 if (lens[i])
2893 array[i] = i;
2894 else
2895 array[i] = -1;
2896 }
2897 qsort(array,SIZE(array),sizeof(array[0]),
2898 (int (*)(const void *,const void *)) verify_sun_cmp);
2899 if (array[0] == -1) {
2900 printf(_("No partitions defined\n"));
2901 return;
2902 }
2903 stop = cylinders * heads * sectors;
2904 if (starts[array[0]])
2905 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2906 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2907 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2908 }
2909 start = starts[array[i]]+lens[array[i]];
2910 if (start < stop)
2911 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2912}
2913
2914static void
2915add_sun_partition(int n, int sys) {
2916 uint start, stop, stop2;
2917 uint starts[8], lens[8];
2918 int whole_disk = 0;
2919
2920 char mesg[256];
2921 int i, first, last;
2922
2923 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2924 printf(_("Partition %d is already defined. Delete "
2925 "it before re-adding it.\n"), n + 1);
2926 return;
2927 }
2928
2929 fetch_sun(starts,lens,&start,&stop);
2930 if (stop <= start) {
2931 if (n == 2)
2932 whole_disk = 1;
2933 else {
2934 printf(_("Other partitions already cover the whole disk.\nDelete "
2935 "some/shrink them before retry.\n"));
2936 return;
2937 }
2938 }
2939 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2940 for (;;) {
2941 if (whole_disk)
2942 first = read_int(0, 0, 0, 0, mesg);
2943 else
2944 first = read_int(scround(start), scround(stop)+1,
2945 scround(stop), 0, mesg);
2946 if (display_in_cyl_units)
2947 first *= units_per_sector;
2948 else
2949 /* Starting sector has to be properly aligned */
2950 first = (first + heads * sectors - 1) / (heads * sectors);
2951 if (n == 2 && first != 0)
2952 printf ("\
2953It is highly recommended that the third partition covers the whole disk\n\
2954and is of type `Whole disk'\n");
2955 /* ewt asks to add: "don't start a partition at cyl 0"
2956 However, edmundo@rano.demon.co.uk writes:
2957 "In addition to having a Sun partition table, to be able to
2958 boot from the disc, the first partition, /dev/sdX1, must
2959 start at cylinder 0. This means that /dev/sdX1 contains
2960 the partition table and the boot block, as these are the
2961 first two sectors of the disc. Therefore you must be
2962 careful what you use /dev/sdX1 for. In particular, you must
2963 not use a partition starting at cylinder 0 for Linux swap,
2964 as that would overwrite the partition table and the boot
2965 block. You may, however, use such a partition for a UFS
2966 or EXT2 file system, as these file systems leave the first
2967 1024 bytes undisturbed. */
2968 /* On the other hand, one should not use partitions
2969 starting at block 0 in an md, or the label will
2970 be trashed. */
2971 for (i = 0; i < partitions; i++)
2972 if (lens[i] && starts[i] <= first
2973 && starts[i] + lens[i] > first)
2974 break;
2975 if (i < partitions && !whole_disk) {
2976 if (n == 2 && !first) {
2977 whole_disk = 1;
2978 break;
2979 }
2980 printf(_("Sector %d is already allocated\n"), first);
2981 } else
2982 break;
2983 }
2984 stop = cylinders * heads * sectors;
2985 stop2 = stop;
2986 for (i = 0; i < partitions; i++) {
2987 if (starts[i] > first && starts[i] < stop)
2988 stop = starts[i];
2989 }
2990 snprintf(mesg, sizeof(mesg),
2991 _("Last %s or +size or +sizeM or +sizeK"),
2992 str_units(SINGULAR));
2993 if (whole_disk)
2994 last = read_int(scround(stop2), scround(stop2), scround(stop2),
2995 0, mesg);
2996 else if (n == 2 && !first)
2997 last = read_int(scround(first), scround(stop2), scround(stop2),
2998 scround(first), mesg);
2999 else
3000 last = read_int(scround(first), scround(stop), scround(stop),
3001 scround(first), mesg);
3002 if (display_in_cyl_units)
3003 last *= units_per_sector;
3004 if (n == 2 && !first) {
3005 if (last >= stop2) {
3006 whole_disk = 1;
3007 last = stop2;
3008 } else if (last > stop) {
3009 printf (
3010 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
3011 "%d %s covers some other partition. Your entry has been changed\n"
3012 "to %d %s\n"),
3013 scround(last), str_units(SINGULAR),
3014 scround(stop), str_units(SINGULAR));
3015 last = stop;
3016 }
3017 } else if (!whole_disk && last > stop)
3018 last = stop;
3019
3020 if (whole_disk) sys = WHOLE_DISK;
3021 set_sun_partition(n, first, last, sys);
3022}
3023
3024static void
3025sun_delete_partition(int i) {
Eric Andersen040f4402003-07-30 08:40:37 +00003026 unsigned int nsec;
3027
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003028 if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
3029 !sunlabel->partitions[i].start_cylinder &&
Eric Andersen040f4402003-07-30 08:40:37 +00003030 (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003031 == heads * sectors * cylinders)
3032 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3033 "consider leaving this\n"
3034 "partition as Whole disk (5), starting at 0, with %u "
Eric Andersen040f4402003-07-30 08:40:37 +00003035 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003036 sunlabel->infos[i].id = 0;
3037 sunlabel->partitions[i].num_sectors = 0;
3038}
3039
3040static void
3041sun_change_sysid(int i, int sys) {
3042 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3043 read_chars(
3044 _("It is highly recommended that the partition at offset 0\n"
3045 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3046 "there may destroy your partition table and bootblock.\n"
3047 "Type YES if you're very sure you would like that partition\n"
3048 "tagged with 82 (Linux swap): "));
3049 if (strcmp (line_ptr, _("YES\n")))
3050 return;
3051 }
3052 switch (sys) {
3053 case SUNOS_SWAP:
3054 case LINUX_SWAP:
3055 /* swaps are not mountable by default */
3056 sunlabel->infos[i].flags |= 0x01;
3057 break;
3058 default:
3059 /* assume other types are mountable;
3060 user can change it anyway */
3061 sunlabel->infos[i].flags &= ~0x01;
3062 break;
3063 }
3064 sunlabel->infos[i].id = sys;
3065}
3066
3067static void
3068sun_list_table(int xtra) {
3069 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003070
3071 w = strlen(disk_device);
3072 if (xtra)
3073 printf(
3074 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3075 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3076 "%d extra sects/cyl, interleave %d:1\n"
3077 "%s\n"
3078 "Units = %s of %d * 512 bytes\n\n"),
3079 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3080 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3081 SUN_SSWAP16(sunlabel->pcylcount),
3082 SUN_SSWAP16(sunlabel->sparecyl),
3083 SUN_SSWAP16(sunlabel->ilfact),
3084 (char *)sunlabel,
3085 str_units(PLURAL), units_per_sector);
3086 else
3087 printf(
3088 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3089 "Units = %s of %d * 512 bytes\n\n"),
3090 disk_device, heads, sectors, cylinders,
3091 str_units(PLURAL), units_per_sector);
3092
3093 printf(_("%*s Flag Start End Blocks Id System\n"),
3094 w + 1, _("Device"));
3095 for (i = 0 ; i < partitions; i++) {
3096 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003097 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3098 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003099 printf(
3100 "%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3101/* device */ partname(disk_device, i+1, w),
3102/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
3103 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3104/* start */ (long) scround(start),
3105/* end */ (long) scround(start+len),
3106/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
3107/* type id */ sunlabel->infos[i].id,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003108/* type name */ partition_type(sunlabel->infos[i].id));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003109 }
3110 }
3111}
3112
Eric Andersen040f4402003-07-30 08:40:37 +00003113#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3114
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003115static void
3116sun_set_alt_cyl(void) {
3117 sunlabel->nacyl =
3118 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3119 _("Number of alternate cylinders")));
3120}
3121
3122static void
3123sun_set_ncyl(int cyl) {
3124 sunlabel->ncyl = SUN_SSWAP16(cyl);
3125}
3126
3127static void
3128sun_set_xcyl(void) {
3129 sunlabel->sparecyl =
3130 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3131 _("Extra sectors per cylinder")));
3132}
3133
3134static void
3135sun_set_ilfact(void) {
3136 sunlabel->ilfact =
3137 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3138 _("Interleave factor")));
3139}
3140
3141static void
3142sun_set_rspeed(void) {
3143 sunlabel->rspeed =
3144 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3145 _("Rotation speed (rpm)")));
3146}
3147
3148static void
3149sun_set_pcylcount(void) {
3150 sunlabel->pcylcount =
3151 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3152 _("Number of physical cylinders")));
3153}
Eric Andersen040f4402003-07-30 08:40:37 +00003154#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003155
3156static void
3157sun_write_table(void) {
3158 unsigned short *ush = (unsigned short *)sunlabel;
3159 unsigned short csum = 0;
3160
3161 while(ush < (unsigned short *)(&sunlabel->csum))
3162 csum ^= *ush++;
3163 sunlabel->csum = csum;
3164 if (lseek(fd, 0, SEEK_SET) < 0)
3165 fdisk_fatal(unable_to_seek);
3166 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3167 fdisk_fatal(unable_to_write);
3168}
3169#endif /* SUN_LABEL */
3170
3171/* DOS partition types */
3172
3173static const struct systypes i386_sys_types[] = {
3174 {"\x00" "Empty"},
3175 {"\x01" "FAT12"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003176 {"\x04" "FAT16 <32M"},
3177 {"\x05" "Extended"}, /* DOS 3.3+ extended partition */
3178 {"\x06" "FAT16"}, /* DOS 16-bit >=32M */
3179 {"\x07" "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003180 {"\x0a" "OS/2 Boot Manager"},/* OS/2 Boot Manager */
3181 {"\x0b" "Win95 FAT32"},
3182 {"\x0c" "Win95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
3183 {"\x0e" "Win95 FAT16 (LBA)"},
3184 {"\x0f" "Win95 Ext'd (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003185 {"\x11" "Hidden FAT12"},
3186 {"\x12" "Compaq diagnostics"},
3187 {"\x14" "Hidden FAT16 <32M"},
3188 {"\x16" "Hidden FAT16"},
3189 {"\x17" "Hidden HPFS/NTFS"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003190 {"\x1b" "Hidden Win95 FAT32"},
3191 {"\x1c" "Hidden Win95 FAT32 (LBA)"},
3192 {"\x1e" "Hidden Win95 FAT16 (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003193 {"\x3c" "PartitionMagic recovery"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003194 {"\x41" "PPC PReP Boot"},
3195 {"\x42" "SFS"},
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003196 {"\x63" "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3197 {"\x80" "Old Minix"}, /* Minix 1.4a and earlier */
3198 {"\x81" "Minix / old Linux"},/* Minix 1.4b and later */
3199 {"\x82" "Linux swap"}, /* also Solaris */
3200 {"\x83" "Linux"},
3201 {"\x84" "OS/2 hidden C: drive"},
3202 {"\x85" "Linux extended"},
3203 {"\x86" "NTFS volume set"},
3204 {"\x87" "NTFS volume set"},
3205 {"\x8e" "Linux LVM"},
3206 {"\x9f" "BSD/OS"}, /* BSDI */
3207 {"\xa0" "IBM Thinkpad hibernation"},
3208 {"\xa5" "FreeBSD"}, /* various BSD flavours */
3209 {"\xa6" "OpenBSD"},
3210 {"\xa8" "Darwin UFS"},
3211 {"\xa9" "NetBSD"},
3212 {"\xab" "Darwin boot"},
3213 {"\xb7" "BSDI fs"},
3214 {"\xb8" "BSDI swap"},
3215 {"\xbe" "Solaris boot"},
3216 {"\xeb" "BeOS fs"},
3217 {"\xee" "EFI GPT"}, /* Intel EFI GUID Partition Table */
3218 {"\xef" "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
3219 {"\xf0" "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
3220 {"\xf2" "DOS secondary"}, /* DOS 3.3+ secondary */
3221 {"\xfd" "Linux raid autodetect"},/* New (2.2.x) raid partition with
3222 autodetect using persistent
3223 superblock */
3224#ifdef CONFIG_WEIRD_PARTITION_TYPES
3225 {"\x02" "XENIX root"},
3226 {"\x03" "XENIX usr"},
3227 {"\x08" "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3228 {"\x09" "AIX bootable"}, /* AIX data or Coherent */
3229 {"\x10" "OPUS"},
3230 {"\x18" "AST SmartSleep"},
3231 {"\x24" "NEC DOS"},
3232 {"\x39" "Plan 9"},
3233 {"\x40" "Venix 80286"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003234 {"\x4d" "QNX4.x"},
3235 {"\x4e" "QNX4.x 2nd part"},
3236 {"\x4f" "QNX4.x 3rd part"},
3237 {"\x50" "OnTrack DM"},
3238 {"\x51" "OnTrack DM6 Aux1"}, /* (or Novell) */
3239 {"\x52" "CP/M"}, /* CP/M or Microport SysV/AT */
3240 {"\x53" "OnTrack DM6 Aux3"},
3241 {"\x54" "OnTrackDM6"},
3242 {"\x55" "EZ-Drive"},
3243 {"\x56" "Golden Bow"},
3244 {"\x5c" "Priam Edisk"},
3245 {"\x61" "SpeedStor"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003246 {"\x64" "Novell Netware 286"},
3247 {"\x65" "Novell Netware 386"},
3248 {"\x70" "DiskSecure Multi-Boot"},
3249 {"\x75" "PC/IX"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003250 {"\x93" "Amoeba"},
3251 {"\x94" "Amoeba BBT"}, /* (bad block table) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003252 {"\xa7" "NeXTSTEP"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003253 {"\xbb" "Boot Wizard hidden"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003254 {"\xc1" "DRDOS/sec (FAT-12)"},
3255 {"\xc4" "DRDOS/sec (FAT-16 < 32M)"},
3256 {"\xc6" "DRDOS/sec (FAT-16)"},
3257 {"\xc7" "Syrinx"},
3258 {"\xda" "Non-FS data"},
3259 {"\xdb" "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
3260 Concurrent DOS or CTOS */
3261 {"\xde" "Dell Utility"}, /* Dell PowerEdge Server utilities */
3262 {"\xdf" "BootIt"}, /* BootIt EMBRM */
3263 {"\xe1" "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
3264 extended partition */
3265 {"\xe3" "DOS R/O"}, /* DOS R/O or SpeedStor */
3266 {"\xe4" "SpeedStor"}, /* SpeedStor 16-bit FAT extended
3267 partition < 1024 cyl. */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003268 {"\xf1" "SpeedStor"},
3269 {"\xf4" "SpeedStor"}, /* SpeedStor large partition */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003270 {"\xfe" "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
3271 {"\xff" "BBT"}, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003272#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003273 { 0 }
3274};
3275
3276
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003277
3278/* A valid partition table sector ends in 0x55 0xaa */
3279static unsigned int
3280part_table_flag(const char *b) {
3281 return ((uint) b[510]) + (((uint) b[511]) << 8);
3282}
3283
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003284
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003285#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003286static void
3287write_part_table_flag(char *b) {
3288 b[510] = 0x55;
3289 b[511] = 0xaa;
3290}
3291
3292/* start_sect and nr_sects are stored little endian on all machines */
3293/* moreover, they are not aligned correctly */
3294static void
3295store4_little_endian(unsigned char *cp, unsigned int val) {
3296 cp[0] = (val & 0xff);
3297 cp[1] = ((val >> 8) & 0xff);
3298 cp[2] = ((val >> 16) & 0xff);
3299 cp[3] = ((val >> 24) & 0xff);
3300}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003301#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003302
3303static unsigned int
3304read4_little_endian(const unsigned char *cp) {
3305 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3306 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3307}
3308
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003309#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003310static void
3311set_start_sect(struct partition *p, unsigned int start_sect) {
3312 store4_little_endian(p->start4, start_sect);
3313}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003314#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003315
3316static unsigned int
3317get_start_sect(const struct partition *p) {
3318 return read4_little_endian(p->start4);
3319}
3320
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003321#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003322static void
3323set_nr_sects(struct partition *p, unsigned int nr_sects) {
3324 store4_little_endian(p->size4, nr_sects);
3325}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003326#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003327
3328static unsigned int
3329get_nr_sects(const struct partition *p) {
3330 return read4_little_endian(p->size4);
3331}
3332
3333/* normally O_RDWR, -l option gives O_RDONLY */
3334static int type_open = O_RDWR;
3335
3336
3337static int ext_index, /* the prime extended partition */
3338 listing, /* no aborts for fdisk -l */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003339 dos_compatible_flag = ~0;
3340#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3341static int dos_changed;
3342static int nowarn; /* no warnings for fdisk -l/-s */
3343#endif
3344
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003345
3346
3347static uint user_cylinders, user_heads, user_sectors;
3348static uint pt_heads, pt_sectors;
3349static uint kern_heads, kern_sectors;
3350
3351static uint extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003352
Eric Andersen040f4402003-07-30 08:40:37 +00003353static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003354
3355
3356static jmp_buf listingbuf;
3357
3358static void fdisk_fatal(enum failure why) {
3359 const char *message;
3360
3361 if (listing) {
3362 close(fd);
3363 longjmp(listingbuf, 1);
3364 }
3365
3366 switch (why) {
3367 case unable_to_open:
3368 message = "Unable to open %s\n";
3369 break;
3370 case unable_to_read:
3371 message = "Unable to read %s\n";
3372 break;
3373 case unable_to_seek:
3374 message = "Unable to seek on %s\n";
3375 break;
3376 case unable_to_write:
3377 message = "Unable to write %s\n";
3378 break;
3379 case ioctl_error:
3380 message = "BLKGETSIZE ioctl failed on %s\n";
3381 break;
3382 default:
3383 message = "Fatal error\n";
3384 }
3385
3386 fputc('\n', stderr);
3387 fprintf(stderr, message, disk_device);
3388 exit(1);
3389}
3390
3391static void
3392seek_sector(uint secno) {
3393 ext2_loff_t offset = (ext2_loff_t) secno * sector_size;
Eric Andersen341170b2003-07-14 19:03:14 +00003394 if (lseek(fd, offset, SEEK_SET) == (ext2_loff_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003395 fdisk_fatal(unable_to_seek);
3396}
3397
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003398#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003399static void
3400write_sector(uint secno, char *buf) {
3401 seek_sector(secno);
3402 if (write(fd, buf, sector_size) != sector_size)
3403 fdisk_fatal(unable_to_write);
3404}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003405#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003406
3407/* Allocate a buffer and read a partition table sector */
3408static void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003409read_pte(struct pte *pe, uint offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003410
3411 pe->offset = offset;
3412 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003413 seek_sector(offset);
3414 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3415 fdisk_fatal(unable_to_read);
3416#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003417 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003418#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003419 pe->part_table = pe->ext_pointer = NULL;
3420}
3421
3422static unsigned int
3423get_partition_start(const struct pte *pe) {
3424 return pe->offset + get_start_sect(pe->part_table);
3425}
3426
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003427#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003428/*
3429 * Avoid warning about DOS partitions when no DOS partition was changed.
3430 * Here a heuristic "is probably dos partition".
3431 * We might also do the opposite and warn in all cases except
3432 * for "is probably nondos partition".
3433 */
3434static int
3435is_dos_partition(int t) {
3436 return (t == 1 || t == 4 || t == 6 ||
3437 t == 0x0b || t == 0x0c || t == 0x0e ||
3438 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3439 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3440 t == 0xc1 || t == 0xc4 || t == 0xc6);
3441}
3442
3443static void
3444menu(void) {
3445#ifdef CONFIG_FEATURE_SUN_LABEL
3446 if (sun_label) {
3447 puts(_("Command action"));
3448 puts(_("\ta\ttoggle a read only flag")); /* sun */
3449 puts(_("\tb\tedit bsd disklabel"));
3450 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3451 puts(_("\td\tdelete a partition"));
3452 puts(_("\tl\tlist known partition types"));
3453 puts(_("\tm\tprint this menu"));
3454 puts(_("\tn\tadd a new partition"));
3455 puts(_("\to\tcreate a new empty DOS partition table"));
3456 puts(_("\tp\tprint the partition table"));
3457 puts(_("\tq\tquit without saving changes"));
3458 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3459 puts(_("\tt\tchange a partition's system id"));
3460 puts(_("\tu\tchange display/entry units"));
3461 puts(_("\tv\tverify the partition table"));
3462 puts(_("\tw\twrite table to disk and exit"));
3463#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3464 puts(_("\tx\textra functionality (experts only)"));
3465#endif
3466 } else
3467#endif
3468#ifdef CONFIG_FEATURE_SGI_LABEL
3469 if (sgi_label) {
3470 puts(_("Command action"));
3471 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3472 puts(_("\tb\tedit bootfile entry")); /* sgi */
3473 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3474 puts(_("\td\tdelete a partition"));
3475 puts(_("\tl\tlist known partition types"));
3476 puts(_("\tm\tprint this menu"));
3477 puts(_("\tn\tadd a new partition"));
3478 puts(_("\to\tcreate a new empty DOS partition table"));
3479 puts(_("\tp\tprint the partition table"));
3480 puts(_("\tq\tquit without saving changes"));
3481 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3482 puts(_("\tt\tchange a partition's system id"));
3483 puts(_("\tu\tchange display/entry units"));
3484 puts(_("\tv\tverify the partition table"));
3485 puts(_("\tw\twrite table to disk and exit"));
3486 } else
3487#endif
3488#ifdef CONFIG_FEATURE_AIX_LABEL
3489 if (aix_label) {
3490 puts(_("Command action"));
3491 puts(_("\tm\tprint this menu"));
3492 puts(_("\to\tcreate a new empty DOS partition table"));
3493 puts(_("\tq\tquit without saving changes"));
3494 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3495 } else
3496#endif
3497 {
3498 puts(_("Command action"));
3499 puts(_("\ta\ttoggle a bootable flag"));
3500 puts(_("\tb\tedit bsd disklabel"));
3501 puts(_("\tc\ttoggle the dos compatibility flag"));
3502 puts(_("\td\tdelete a partition"));
3503 puts(_("\tl\tlist known partition types"));
3504 puts(_("\tm\tprint this menu"));
3505 puts(_("\tn\tadd a new partition"));
3506 puts(_("\to\tcreate a new empty DOS partition table"));
3507 puts(_("\tp\tprint the partition table"));
3508 puts(_("\tq\tquit without saving changes"));
3509 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3510 puts(_("\tt\tchange a partition's system id"));
3511 puts(_("\tu\tchange display/entry units"));
3512 puts(_("\tv\tverify the partition table"));
3513 puts(_("\tw\twrite table to disk and exit"));
3514#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3515 puts(_("\tx\textra functionality (experts only)"));
3516#endif
3517 }
3518}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003519#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3520
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003521
3522#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3523static void
3524xmenu(void) {
3525#ifdef CONFIG_FEATURE_SUN_LABEL
3526 if (sun_label) {
3527 puts(_("Command action"));
3528 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3529 puts(_("\tc\tchange number of cylinders"));
3530 puts(_("\td\tprint the raw data in the partition table"));
3531 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3532 puts(_("\th\tchange number of heads"));
3533 puts(_("\ti\tchange interleave factor")); /*sun*/
3534 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3535 puts(_("\tm\tprint this menu"));
3536 puts(_("\tp\tprint the partition table"));
3537 puts(_("\tq\tquit without saving changes"));
3538 puts(_("\tr\treturn to main menu"));
3539 puts(_("\ts\tchange number of sectors/track"));
3540 puts(_("\tv\tverify the partition table"));
3541 puts(_("\tw\twrite table to disk and exit"));
3542 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
3543 } else
3544#endif
3545#ifdef CONFIG_FEATURE_SGI_LABEL
3546 if (sgi_label) {
3547 puts(_("Command action"));
3548 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3549 puts(_("\tc\tchange number of cylinders"));
3550 puts(_("\td\tprint the raw data in the partition table"));
3551 puts(_("\te\tlist extended partitions")); /* !sun */
3552 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3553 puts(_("\th\tchange number of heads"));
3554 puts(_("\tm\tprint this menu"));
3555 puts(_("\tp\tprint the partition table"));
3556 puts(_("\tq\tquit without saving changes"));
3557 puts(_("\tr\treturn to main menu"));
3558 puts(_("\ts\tchange number of sectors/track"));
3559 puts(_("\tv\tverify the partition table"));
3560 puts(_("\tw\twrite table to disk and exit"));
3561 } else
3562#endif
3563#ifdef CONFIG_FEATURE_AIX_LABEL
3564 if (aix_label) {
3565 puts(_("Command action"));
3566 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3567 puts(_("\tc\tchange number of cylinders"));
3568 puts(_("\td\tprint the raw data in the partition table"));
3569 puts(_("\te\tlist extended partitions")); /* !sun */
3570 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3571 puts(_("\th\tchange number of heads"));
3572 puts(_("\tm\tprint this menu"));
3573 puts(_("\tp\tprint the partition table"));
3574 puts(_("\tq\tquit without saving changes"));
3575 puts(_("\tr\treturn to main menu"));
3576 puts(_("\ts\tchange number of sectors/track"));
3577 puts(_("\tv\tverify the partition table"));
3578 puts(_("\tw\twrite table to disk and exit"));
3579 } else
3580#endif
3581 {
3582 puts(_("Command action"));
3583 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3584 puts(_("\tc\tchange number of cylinders"));
3585 puts(_("\td\tprint the raw data in the partition table"));
3586 puts(_("\te\tlist extended partitions")); /* !sun */
3587 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
3588#ifdef CONFIG_FEATURE_SGI_LABEL
3589 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3590#endif
3591 puts(_("\th\tchange number of heads"));
3592 puts(_("\tm\tprint this menu"));
3593 puts(_("\tp\tprint the partition table"));
3594 puts(_("\tq\tquit without saving changes"));
3595 puts(_("\tr\treturn to main menu"));
3596 puts(_("\ts\tchange number of sectors/track"));
3597 puts(_("\tv\tverify the partition table"));
3598 puts(_("\tw\twrite table to disk and exit"));
3599 }
3600}
3601#endif /* ADVANCED mode */
3602
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003603#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003604static const struct systypes *
3605get_sys_types(void) {
3606 return (
3607#ifdef CONFIG_FEATURE_SUN_LABEL
3608 sun_label ? sun_sys_types :
3609#endif
3610#ifdef CONFIG_FEATURE_SGI_LABEL
3611 sgi_label ? sgi_sys_types :
3612#endif
3613 i386_sys_types);
3614}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003615#else
3616#define get_sys_types() i386_sys_types
3617#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003618
3619static const char *partition_type(unsigned char type)
3620{
3621 int i;
3622 const struct systypes *types = get_sys_types();
3623
3624 for (i=0; types[i].name; i++)
3625 if (types[i].name[0] == type)
3626 return types[i].name + 1;
3627
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003628 return _("Unknown");
3629}
3630
3631
3632#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3633static int
3634get_sysid(int i) {
3635 return (
3636#ifdef CONFIG_FEATURE_SUN_LABEL
3637 sun_label ? sunlabel->infos[i].id :
3638#endif
3639#ifdef CONFIG_FEATURE_SGI_LABEL
3640 sgi_label ? sgi_get_sysid(i) :
3641#endif
3642 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003643}
3644
3645void list_types(const struct systypes *sys)
3646{
3647 uint last[4], done = 0, next = 0, size;
3648 int i;
3649
3650 for (i = 0; sys[i].name; i++);
3651 size = i;
3652
3653 for (i = 3; i >= 0; i--)
3654 last[3 - i] = done += (size + i - done) / (i + 1);
3655 i = done = 0;
3656
3657 do {
3658 printf("%c%2x %-15.15s", i ? ' ' : '\n',
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003659 sys[next].name[0], partition_type(sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003660 next = last[i++] + done;
3661 if (i > 3 || next >= last[i]) {
3662 i = 0;
3663 next = ++done;
3664 }
3665 } while (done < last[0]);
3666 putchar('\n');
3667}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003668#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003669
3670static int
3671is_cleared_partition(const struct partition *p) {
3672 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3673 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3674 get_start_sect(p) || get_nr_sects(p));
3675}
3676
3677static void
3678clear_partition(struct partition *p) {
3679 if (!p)
3680 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003681 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003682}
3683
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003684#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003685static void
3686set_partition(int i, int doext, uint start, uint stop, int sysid) {
3687 struct partition *p;
3688 uint offset;
3689
3690 if (doext) {
3691 p = ptes[i].ext_pointer;
3692 offset = extended_offset;
3693 } else {
3694 p = ptes[i].part_table;
3695 offset = ptes[i].offset;
3696 }
3697 p->boot_ind = 0;
3698 p->sys_ind = sysid;
3699 set_start_sect(p, start - offset);
3700 set_nr_sects(p, stop - start + 1);
3701 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3702 start = heads*sectors*1024 - 1;
3703 set_hsc(p->head, p->sector, p->cyl, start);
3704 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3705 stop = heads*sectors*1024 - 1;
3706 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3707 ptes[i].changed = 1;
3708}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003709#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003710
3711static int
3712test_c(const char **m, const char *mesg) {
3713 int val = 0;
3714 if (!*m)
3715 fprintf(stderr, _("You must set"));
3716 else {
3717 fprintf(stderr, " %s", *m);
3718 val = 1;
3719 }
3720 *m = mesg;
3721 return val;
3722}
3723
3724static int
3725warn_geometry(void) {
3726 const char *m = NULL;
3727 int prev = 0;
3728
3729 if (!heads)
3730 prev = test_c(&m, _("heads"));
3731 if (!sectors)
3732 prev = test_c(&m, _("sectors"));
3733 if (!cylinders)
3734 prev = test_c(&m, _("cylinders"));
3735 if (!m)
3736 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003737
3738 fprintf(stderr, "%s%s.\n"
3739#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3740 "You can do this from the extra functions menu.\n"
3741#endif
3742 , prev ? _(" and ") : " ", m);
3743
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003744 return 1;
3745}
3746
3747static void update_units(void)
3748{
3749 int cyl_units = heads * sectors;
3750
3751 if (display_in_cyl_units && cyl_units)
3752 units_per_sector = cyl_units;
3753 else
3754 units_per_sector = 1; /* in sectors */
3755}
3756
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003757#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003758static void
3759warn_cylinders(void) {
3760 if (dos_label && cylinders > 1024 && !nowarn)
3761 fprintf(stderr, _("\n"
3762"The number of cylinders for this disk is set to %d.\n"
3763"There is nothing wrong with that, but this is larger than 1024,\n"
3764"and could in certain setups cause problems with:\n"
3765"1) software that runs at boot time (e.g., old versions of LILO)\n"
3766"2) booting and partitioning software from other OSs\n"
3767" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3768 cylinders);
3769}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003770#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003771
3772static void
3773read_extended(int ext) {
3774 int i;
3775 struct pte *pex;
3776 struct partition *p, *q;
3777
3778 ext_index = ext;
3779 pex = &ptes[ext];
3780 pex->ext_pointer = pex->part_table;
3781
3782 p = pex->part_table;
3783 if (!get_start_sect(p)) {
3784 fprintf(stderr,
3785 _("Bad offset in primary extended partition\n"));
3786 return;
3787 }
3788
3789 while (IS_EXTENDED (p->sys_ind)) {
3790 struct pte *pe = &ptes[partitions];
3791
3792 if (partitions >= MAXIMUM_PARTS) {
3793 /* This is not a Linux restriction, but
3794 this program uses arrays of size MAXIMUM_PARTS.
3795 Do not try to `improve' this test. */
3796 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003797#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003798 fprintf(stderr,
3799 _("Warning: deleting partitions after %d\n"),
3800 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003801 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003802#endif
3803 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003804 return;
3805 }
3806
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003807 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003808
3809 if (!extended_offset)
3810 extended_offset = get_start_sect(p);
3811
3812 q = p = pt_offset(pe->sectorbuffer, 0);
3813 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3814 if (IS_EXTENDED (p->sys_ind)) {
3815 if (pe->ext_pointer)
3816 fprintf(stderr,
3817 _("Warning: extra link "
3818 "pointer in partition table"
3819 " %d\n"), partitions + 1);
3820 else
3821 pe->ext_pointer = p;
3822 } else if (p->sys_ind) {
3823 if (pe->part_table)
3824 fprintf(stderr,
3825 _("Warning: ignoring extra "
3826 "data in partition table"
3827 " %d\n"), partitions + 1);
3828 else
3829 pe->part_table = p;
3830 }
3831 }
3832
3833 /* very strange code here... */
3834 if (!pe->part_table) {
3835 if (q != pe->ext_pointer)
3836 pe->part_table = q;
3837 else
3838 pe->part_table = q + 1;
3839 }
3840 if (!pe->ext_pointer) {
3841 if (q != pe->part_table)
3842 pe->ext_pointer = q;
3843 else
3844 pe->ext_pointer = q + 1;
3845 }
3846
3847 p = pe->ext_pointer;
3848 partitions++;
3849 }
3850
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003851#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003852 /* remove empty links */
3853 remove:
3854 for (i = 4; i < partitions; i++) {
3855 struct pte *pe = &ptes[i];
3856
3857 if (!get_nr_sects(pe->part_table) &&
3858 (partitions > 5 || ptes[4].part_table->sys_ind)) {
3859 printf("omitting empty partition (%d)\n", i+1);
3860 delete_partition(i);
3861 goto remove; /* numbering changed */
3862 }
3863 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003864#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003865}
3866
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003867#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003868static void
3869create_doslabel(void) {
3870 int i;
3871
3872 fprintf(stderr,
3873 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3874 "until you decide to write them. After that, of course, the previous\n"
3875 "content won't be recoverable.\n\n"));
3876#ifdef CONFIG_FEATURE_SUN_LABEL
3877 sun_nolabel(); /* otherwise always recognised as sun */
3878#endif
3879#ifdef CONFIG_FEATURE_SGI_LABEL
3880 sgi_nolabel(); /* otherwise always recognised as sgi */
3881#endif
3882#ifdef CONFIG_FEATURE_AIX_LABEL
3883 aix_label = 0;
3884#endif
3885#ifdef CONFIG_FEATURE_OSF_LABEL
3886 osf_label = 0;
3887 possibly_osf_label = 0;
3888#endif
3889 partitions = 4;
3890
3891 for (i = 510-64; i < 510; i++)
3892 MBRbuffer[i] = 0;
3893 write_part_table_flag(MBRbuffer);
3894 extended_offset = 0;
3895 set_all_unchanged();
3896 set_changed(0);
3897 get_boot(create_empty_dos);
3898}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003899#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003900
3901static void
3902get_sectorsize(void) {
3903 if (!user_set_sector_size &&
3904 get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
3905 int arg;
3906 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3907 sector_size = arg;
3908 if (sector_size != DEFAULT_SECTOR_SIZE)
3909 printf(_("Note: sector size is %d (not %d)\n"),
3910 sector_size, DEFAULT_SECTOR_SIZE);
3911 }
3912}
3913
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003914static inline void
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003915get_kernel_geometry(void) {
3916 struct hd_geometry geometry;
3917
3918 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3919 kern_heads = geometry.heads;
3920 kern_sectors = geometry.sectors;
3921 /* never use geometry.cylinders - it is truncated */
3922 }
3923}
3924
3925static void
3926get_partition_table_geometry(void) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003927 const unsigned char *bufp = MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003928 struct partition *p;
3929 int i, h, s, hh, ss;
3930 int first = 1;
3931 int bad = 0;
3932
3933 if (!(valid_part_table_flag(bufp)))
3934 return;
3935
3936 hh = ss = 0;
3937 for (i=0; i<4; i++) {
3938 p = pt_offset(bufp, i);
3939 if (p->sys_ind != 0) {
3940 h = p->end_head + 1;
3941 s = (p->end_sector & 077);
3942 if (first) {
3943 hh = h;
3944 ss = s;
3945 first = 0;
3946 } else if (hh != h || ss != s)
3947 bad = 1;
3948 }
3949 }
3950
3951 if (!first && !bad) {
3952 pt_heads = hh;
3953 pt_sectors = ss;
3954 }
3955}
3956
3957void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003958get_geometry(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003959 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003960 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003961
3962 get_sectorsize();
3963 sec_fac = sector_size / 512;
3964#ifdef CONFIG_FEATURE_SUN_LABEL
3965 guess_device_type();
3966#endif
3967 heads = cylinders = sectors = 0;
3968 kern_heads = kern_sectors = 0;
3969 pt_heads = pt_sectors = 0;
3970
3971 get_kernel_geometry();
3972 get_partition_table_geometry();
3973
3974 heads = user_heads ? user_heads :
3975 pt_heads ? pt_heads :
3976 kern_heads ? kern_heads : 255;
3977 sectors = user_sectors ? user_sectors :
3978 pt_sectors ? pt_sectors :
3979 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003980 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3981 /* got bytes */
3982 } else {
3983 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003984
3985 if (ioctl(fd, BLKGETSIZE, &longsectors))
3986 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00003987 bytes = ((unsigned long long) longsectors) << 9;
3988 }
3989
3990 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003991
3992 sector_offset = 1;
3993 if (dos_compatible_flag)
3994 sector_offset = sectors;
3995
Eric Andersen040f4402003-07-30 08:40:37 +00003996 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003997 if (!cylinders)
3998 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003999}
4000
4001/*
4002 * Read MBR. Returns:
4003 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4004 * 0: found or created label
4005 * 1: I/O error
4006 */
4007int
4008get_boot(enum action what) {
4009 int i;
4010
4011 partitions = 4;
4012
4013 for (i = 0; i < 4; i++) {
4014 struct pte *pe = &ptes[i];
4015
4016 pe->part_table = pt_offset(MBRbuffer, i);
4017 pe->ext_pointer = NULL;
4018 pe->offset = 0;
4019 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004020#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004021 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004022#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004023 }
4024
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004025#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004026 if (what == create_empty_sun && check_sun_label())
4027 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004028#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004029
4030 memset(MBRbuffer, 0, 512);
4031
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004032#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004033 if (what == create_empty_dos)
4034 goto got_dos_table; /* skip reading disk */
4035
4036 if ((fd = open(disk_device, type_open)) < 0) {
4037 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4038 if (what == try_only)
4039 return 1;
4040 fdisk_fatal(unable_to_open);
4041 } else
4042 printf(_("You will not be able to write "
4043 "the partition table.\n"));
4044 }
4045
4046 if (512 != read(fd, MBRbuffer, 512)) {
4047 if (what == try_only)
4048 return 1;
4049 fdisk_fatal(unable_to_read);
4050 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004051#else
4052 if ((fd = open(disk_device, O_RDONLY)) < 0)
4053 return 1;
4054 if (512 != read(fd, MBRbuffer, 512))
4055 return 1;
4056#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004057
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004058 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004059
4060 update_units();
4061
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004062#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004063 if (check_sun_label())
4064 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004065#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004066
4067#ifdef CONFIG_FEATURE_SGI_LABEL
4068 if (check_sgi_label())
4069 return 0;
4070#endif
4071
4072#ifdef CONFIG_FEATURE_AIX_LABEL
4073 if (check_aix_label())
4074 return 0;
4075#endif
4076
4077#ifdef CONFIG_FEATURE_OSF_LABEL
4078 if (check_osf_label()) {
4079 possibly_osf_label = 1;
4080 if (!valid_part_table_flag(MBRbuffer)) {
4081 osf_label = 1;
4082 return 0;
4083 }
4084 printf(_("This disk has both DOS and BSD magic.\n"
4085 "Give the 'b' command to go to BSD mode.\n"));
4086 }
4087#endif
4088
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004089#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004090got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004091#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004092
4093 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004094#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4095 return -1;
4096#else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004097 switch(what) {
4098 case fdisk:
4099 fprintf(stderr,
4100 _("Device contains neither a valid DOS "
4101 "partition table, nor Sun, SGI or OSF "
4102 "disklabel\n"));
4103#ifdef __sparc__
4104#ifdef CONFIG_FEATURE_SUN_LABEL
4105 create_sunlabel();
4106#endif
4107#else
4108 create_doslabel();
4109#endif
4110 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004111 case try_only:
4112 return -1;
4113 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004114#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004115 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004116#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004117 break;
4118 default:
4119 fprintf(stderr, _("Internal error\n"));
4120 exit(1);
4121 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004122#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004123 }
4124
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004125#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004126 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004127#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004128 warn_geometry();
4129
4130 for (i = 0; i < 4; i++) {
4131 struct pte *pe = &ptes[i];
4132
4133 if (IS_EXTENDED (pe->part_table->sys_ind)) {
4134 if (partitions != 4)
4135 fprintf(stderr, _("Ignoring extra extended "
4136 "partition %d\n"), i + 1);
4137 else
4138 read_extended(i);
4139 }
4140 }
4141
4142 for (i = 3; i < partitions; i++) {
4143 struct pte *pe = &ptes[i];
4144
4145 if (!valid_part_table_flag(pe->sectorbuffer)) {
4146 fprintf(stderr,
4147 _("Warning: invalid flag 0x%04x of partition "
4148 "table %d will be corrected by w(rite)\n"),
4149 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004150#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004151 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004152#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004153 }
4154 }
4155
4156 return 0;
4157}
4158
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004159#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004160/*
4161 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4162 * If the user hits Enter, DFLT is returned.
4163 * Answers like +10 are interpreted as offsets from BASE.
4164 *
4165 * There is no default if DFLT is not between LOW and HIGH.
4166 */
4167static uint
4168read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4169{
4170 uint i;
4171 int default_ok = 1;
4172 static char *ms = NULL;
4173 static int mslen = 0;
4174
4175 if (!ms || strlen(mesg)+100 > mslen) {
4176 mslen = strlen(mesg)+200;
4177 ms = xrealloc(ms,mslen);
4178 }
4179
4180 if (dflt < low || dflt > high)
4181 default_ok = 0;
4182
4183 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004184 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004185 mesg, low, high, dflt);
4186 else
Eric Andersen040f4402003-07-30 08:40:37 +00004187 snprintf(ms, mslen, "%s (%u-%u): ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004188 mesg, low, high);
4189
4190 while (1) {
4191 int use_default = default_ok;
4192
4193 /* ask question and read answer */
4194 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4195 && *line_ptr != '-' && *line_ptr != '+')
4196 continue;
4197
Eric Andersenc48d49a2003-07-03 10:02:32 +00004198 if (*line_ptr == '+' || *line_ptr == '-') {
4199 int minus = (*line_ptr == '-');
4200 int absolute = 0;
4201
4202 i = atoi(line_ptr+1);
4203
4204 while (isdigit(*++line_ptr))
4205 use_default = 0;
4206
4207 switch (*line_ptr) {
4208 case 'c':
4209 case 'C':
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004210 if (!display_in_cyl_units)
4211 i *= heads * sectors;
4212 break;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004213 case 'K':
Eric Andersen040f4402003-07-30 08:40:37 +00004214 absolute = 1024;
4215 break;
4216 case 'k':
Eric Andersenc48d49a2003-07-03 10:02:32 +00004217 absolute = 1000;
4218 break;
4219 case 'm':
4220 case 'M':
4221 absolute = 1000000;
4222 break;
4223 case 'g':
4224 case 'G':
4225 absolute = 1000000000;
4226 break;
4227 default:
4228 break;
4229 }
4230 if (absolute) {
4231 unsigned long long bytes;
4232 unsigned long unit;
4233
4234 bytes = (unsigned long long) i * absolute;
4235 unit = sector_size * units_per_sector;
4236 bytes += unit/2; /* round */
4237 bytes /= unit;
4238 i = bytes;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004239 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00004240 if (minus)
4241 i = -i;
4242 i += base;
4243 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004244 i = atoi(line_ptr);
4245 while (isdigit(*line_ptr)) {
4246 line_ptr++;
4247 use_default = 0;
4248 }
4249 }
4250 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004251 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004252 if (i >= low && i <= high)
4253 break;
4254 else
4255 printf(_("Value out of range.\n"));
4256 }
4257 return i;
4258}
4259
4260int
4261get_partition(int warn, int max) {
4262 struct pte *pe;
4263 int i;
4264
4265 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4266 pe = &ptes[i];
4267
4268 if (warn) {
4269 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4270#ifdef CONFIG_FEATURE_SUN_LABEL
4271 || (sun_label &&
4272 (!sunlabel->partitions[i].num_sectors ||
4273 !sunlabel->infos[i].id))
4274#endif
4275#ifdef CONFIG_FEATURE_SGI_LABEL
4276 || (sgi_label && (!sgi_get_num_sectors(i)))
4277#endif
4278 )
4279 fprintf(stderr,
4280 _("Warning: partition %d has empty type\n"),
4281 i+1);
4282 }
4283 return i;
4284}
4285
4286static int
4287get_existing_partition(int warn, int max) {
4288 int pno = -1;
4289 int i;
4290
4291 for (i = 0; i < max; i++) {
4292 struct pte *pe = &ptes[i];
4293 struct partition *p = pe->part_table;
4294
4295 if (p && !is_cleared_partition(p)) {
4296 if (pno >= 0)
4297 goto not_unique;
4298 pno = i;
4299 }
4300 }
4301 if (pno >= 0) {
4302 printf(_("Selected partition %d\n"), pno+1);
4303 return pno;
4304 }
4305 printf(_("No partition is defined yet!\n"));
4306 return -1;
4307
4308 not_unique:
4309 return get_partition(warn, max);
4310}
4311
4312static int
4313get_nonexisting_partition(int warn, int max) {
4314 int pno = -1;
4315 int i;
4316
4317 for (i = 0; i < max; i++) {
4318 struct pte *pe = &ptes[i];
4319 struct partition *p = pe->part_table;
4320
4321 if (p && is_cleared_partition(p)) {
4322 if (pno >= 0)
4323 goto not_unique;
4324 pno = i;
4325 }
4326 }
4327 if (pno >= 0) {
4328 printf(_("Selected partition %d\n"), pno+1);
4329 return pno;
4330 }
4331 printf(_("All primary partitions have been defined already!\n"));
4332 return -1;
4333
4334 not_unique:
4335 return get_partition(warn, max);
4336}
4337
4338
4339void change_units(void)
4340{
4341 display_in_cyl_units = !display_in_cyl_units;
4342 update_units();
4343 printf(_("Changing display/entry units to %s\n"),
4344 str_units(PLURAL));
4345}
4346
4347static void
4348toggle_active(int i) {
4349 struct pte *pe = &ptes[i];
4350 struct partition *p = pe->part_table;
4351
4352 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
4353 fprintf(stderr,
4354 _("WARNING: Partition %d is an extended partition\n"),
4355 i + 1);
4356 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4357 pe->changed = 1;
4358}
4359
4360static void
4361toggle_dos_compatibility_flag(void) {
4362 dos_compatible_flag = ~dos_compatible_flag;
4363 if (dos_compatible_flag) {
4364 sector_offset = sectors;
4365 printf(_("DOS Compatibility flag is set\n"));
4366 }
4367 else {
4368 sector_offset = 1;
4369 printf(_("DOS Compatibility flag is not set\n"));
4370 }
4371}
4372
4373static void
4374delete_partition(int i) {
4375 struct pte *pe = &ptes[i];
4376 struct partition *p = pe->part_table;
4377 struct partition *q = pe->ext_pointer;
4378
4379/* Note that for the fifth partition (i == 4) we don't actually
4380 * decrement partitions.
4381 */
4382
4383 if (warn_geometry())
4384 return; /* C/H/S not set */
4385 pe->changed = 1;
4386
4387#ifdef CONFIG_FEATURE_SUN_LABEL
4388 if (sun_label) {
4389 sun_delete_partition(i);
4390 return;
4391 }
4392#endif
4393#ifdef CONFIG_FEATURE_SGI_LABEL
4394 if (sgi_label) {
4395 sgi_delete_partition(i);
4396 return;
4397 }
4398#endif
4399
4400 if (i < 4) {
4401 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
4402 partitions = 4;
4403 ptes[ext_index].ext_pointer = NULL;
4404 extended_offset = 0;
4405 }
4406 clear_partition(p);
4407 return;
4408 }
4409
4410 if (!q->sys_ind && i > 4) {
4411 /* the last one in the chain - just delete */
4412 --partitions;
4413 --i;
4414 clear_partition(ptes[i].ext_pointer);
4415 ptes[i].changed = 1;
4416 } else {
4417 /* not the last one - further ones will be moved down */
4418 if (i > 4) {
4419 /* delete this link in the chain */
4420 p = ptes[i-1].ext_pointer;
4421 *p = *q;
4422 set_start_sect(p, get_start_sect(q));
4423 set_nr_sects(p, get_nr_sects(q));
4424 ptes[i-1].changed = 1;
4425 } else if (partitions > 5) { /* 5 will be moved to 4 */
4426 /* the first logical in a longer chain */
4427 pe = &ptes[5];
4428
4429 if (pe->part_table) /* prevent SEGFAULT */
4430 set_start_sect(pe->part_table,
4431 get_partition_start(pe) -
4432 extended_offset);
4433 pe->offset = extended_offset;
4434 pe->changed = 1;
4435 }
4436
4437 if (partitions > 5) {
4438 partitions--;
4439 while (i < partitions) {
4440 ptes[i] = ptes[i+1];
4441 i++;
4442 }
4443 } else
4444 /* the only logical: clear only */
4445 clear_partition(ptes[i].part_table);
4446 }
4447}
4448
4449static void
4450change_sysid(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004451 int i, sys, origsys;
4452 struct partition *p;
4453
Eric Andersen040f4402003-07-30 08:40:37 +00004454#ifdef CONFIG_FEATURE_SGI_LABEL
4455 /* If sgi_label then don't use get_existing_partition,
4456 let the user select a partition, since get_existing_partition()
4457 only works for Linux like partition tables. */
4458 if (!sgi_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004459 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004460 } else {
4461 i = get_partition(0, partitions);
4462 }
4463#else
4464 i = get_existing_partition(0, partitions);
4465#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004466 if (i == -1)
4467 return;
4468 p = ptes[i].part_table;
4469 origsys = sys = get_sysid(i);
4470
4471 /* if changing types T to 0 is allowed, then
4472 the reverse change must be allowed, too */
4473 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4474 printf(_("Partition %d does not exist yet!\n"), i + 1);
4475 else while (1) {
4476 sys = read_hex (get_sys_types());
4477
4478 if (!sys && !sgi_label && !sun_label) {
4479 printf(_("Type 0 means free space to many systems\n"
4480 "(but not to Linux). Having partitions of\n"
4481 "type 0 is probably unwise. You can delete\n"
4482 "a partition using the `d' command.\n"));
4483 /* break; */
4484 }
4485
4486 if (!sun_label && !sgi_label) {
4487 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
4488 printf(_("You cannot change a partition into"
4489 " an extended one or vice versa\n"
4490 "Delete it first.\n"));
4491 break;
4492 }
4493 }
4494
4495 if (sys < 256) {
4496#ifdef CONFIG_FEATURE_SUN_LABEL
4497 if (sun_label && i == 2 && sys != WHOLE_DISK)
4498 printf(_("Consider leaving partition 3 "
4499 "as Whole disk (5),\n"
4500 "as SunOS/Solaris expects it and "
4501 "even Linux likes it.\n\n"));
4502#endif
4503#ifdef CONFIG_FEATURE_SGI_LABEL
4504 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4505 || (i == 8 && sys != 0)))
4506 printf(_("Consider leaving partition 9 "
4507 "as volume header (0),\nand "
4508 "partition 11 as entire volume (6)"
4509 "as IRIX expects it.\n\n"));
4510#endif
4511 if (sys == origsys)
4512 break;
4513#ifdef CONFIG_FEATURE_SUN_LABEL
4514 if (sun_label) {
4515 sun_change_sysid(i, sys);
4516 } else
4517#endif
4518#ifdef CONFIG_FEATURE_SGI_LABEL
4519 if (sgi_label) {
4520 sgi_change_sysid(i, sys);
4521 } else
4522#endif
4523 p->sys_ind = sys;
4524 printf (_("Changed system type of partition %d "
4525 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004526 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004527 ptes[i].changed = 1;
4528 if (is_dos_partition(origsys) ||
4529 is_dos_partition(sys))
4530 dos_changed = 1;
4531 break;
4532 }
4533 }
4534}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004535#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4536
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004537
4538/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4539 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4540 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4541 * Lubkin Oct. 1991). */
4542
4543static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
4544 int spc = heads * sectors;
4545
4546 *c = ls / spc;
4547 ls = ls % spc;
4548 *h = ls / sectors;
4549 *s = ls % sectors + 1; /* sectors count from 1 */
4550}
4551
4552static void check_consistency(const struct partition *p, int partition) {
4553 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4554 uint pec, peh, pes; /* physical ending c, h, s */
4555 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4556 uint lec, leh, les; /* logical ending c, h, s */
4557
4558 if (!heads || !sectors || (partition >= 4))
4559 return; /* do not check extended partitions */
4560
4561/* physical beginning c, h, s */
4562 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4563 pbh = p->head;
4564 pbs = p->sector & 0x3f;
4565
4566/* physical ending c, h, s */
4567 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4568 peh = p->end_head;
4569 pes = p->end_sector & 0x3f;
4570
4571/* compute logical beginning (c, h, s) */
4572 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4573
4574/* compute logical ending (c, h, s) */
4575 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4576
4577/* Same physical / logical beginning? */
4578 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4579 printf(_("Partition %d has different physical/logical "
4580 "beginnings (non-Linux?):\n"), partition + 1);
4581 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4582 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4583 }
4584
4585/* Same physical / logical ending? */
4586 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4587 printf(_("Partition %d has different physical/logical "
4588 "endings:\n"), partition + 1);
4589 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4590 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4591 }
4592
4593#if 0
4594/* Beginning on cylinder boundary? */
4595 if (pbh != !pbc || pbs != 1) {
4596 printf(_("Partition %i does not start on cylinder "
4597 "boundary:\n"), partition + 1);
4598 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4599 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4600 }
4601#endif
4602
4603/* Ending on cylinder boundary? */
4604 if (peh != (heads - 1) || pes != sectors) {
Eric Andersenc48d49a2003-07-03 10:02:32 +00004605 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004606 partition + 1);
4607#if 0
4608 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4609 printf(_("should be (%d, %d, %d)\n"),
4610 pec, heads - 1, sectors);
4611#endif
4612 }
4613}
4614
4615static void
4616list_disk_geometry(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00004617 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004618 long megabytes = bytes/1000000;
4619
4620 if (megabytes < 10000)
4621 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4622 disk_device, megabytes, bytes);
4623 else
4624 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4625 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4626 printf(_("%d heads, %d sectors/track, %d cylinders"),
4627 heads, sectors, cylinders);
4628 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004629 printf(_(", total %llu sectors"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004630 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004631 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004632 str_units(PLURAL),
4633 units_per_sector, sector_size, units_per_sector * sector_size);
4634}
4635
4636/*
4637 * Check whether partition entries are ordered by their starting positions.
4638 * Return 0 if OK. Return i if partition i should have been earlier.
4639 * Two separate checks: primary and logical partitions.
4640 */
4641static int
4642wrong_p_order(int *prev) {
4643 const struct pte *pe;
4644 const struct partition *p;
4645 uint last_p_start_pos = 0, p_start_pos;
4646 int i, last_i = 0;
4647
4648 for (i = 0 ; i < partitions; i++) {
4649 if (i == 4) {
4650 last_i = 4;
4651 last_p_start_pos = 0;
4652 }
4653 pe = &ptes[i];
4654 if ((p = pe->part_table)->sys_ind) {
4655 p_start_pos = get_partition_start(pe);
4656
4657 if (last_p_start_pos > p_start_pos) {
4658 if (prev)
4659 *prev = last_i;
4660 return i;
4661 }
4662
4663 last_p_start_pos = p_start_pos;
4664 last_i = i;
4665 }
4666 }
4667 return 0;
4668}
4669
4670#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4671/*
4672 * Fix the chain of logicals.
4673 * extended_offset is unchanged, the set of sectors used is unchanged
4674 * The chain is sorted so that sectors increase, and so that
4675 * starting sectors increase.
4676 *
4677 * After this it may still be that cfdisk doesnt like the table.
4678 * (This is because cfdisk considers expanded parts, from link to
4679 * end of partition, and these may still overlap.)
4680 * Now
4681 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4682 * may help.
4683 */
4684static void
4685fix_chain_of_logicals(void) {
4686 int j, oj, ojj, sj, sjj;
4687 struct partition *pj,*pjj,tmp;
4688
4689 /* Stage 1: sort sectors but leave sector of part 4 */
4690 /* (Its sector is the global extended_offset.) */
4691 stage1:
4692 for (j = 5; j < partitions-1; j++) {
4693 oj = ptes[j].offset;
4694 ojj = ptes[j+1].offset;
4695 if (oj > ojj) {
4696 ptes[j].offset = ojj;
4697 ptes[j+1].offset = oj;
4698 pj = ptes[j].part_table;
4699 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4700 pjj = ptes[j+1].part_table;
4701 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4702 set_start_sect(ptes[j-1].ext_pointer,
4703 ojj-extended_offset);
4704 set_start_sect(ptes[j].ext_pointer,
4705 oj-extended_offset);
4706 goto stage1;
4707 }
4708 }
4709
4710 /* Stage 2: sort starting sectors */
4711 stage2:
4712 for (j = 4; j < partitions-1; j++) {
4713 pj = ptes[j].part_table;
4714 pjj = ptes[j+1].part_table;
4715 sj = get_start_sect(pj);
4716 sjj = get_start_sect(pjj);
4717 oj = ptes[j].offset;
4718 ojj = ptes[j+1].offset;
4719 if (oj+sj > ojj+sjj) {
4720 tmp = *pj;
4721 *pj = *pjj;
4722 *pjj = tmp;
4723 set_start_sect(pj, ojj+sjj-oj);
4724 set_start_sect(pjj, oj+sj-ojj);
4725 goto stage2;
4726 }
4727 }
4728
4729 /* Probably something was changed */
4730 for (j = 4; j < partitions; j++)
4731 ptes[j].changed = 1;
4732}
4733
4734
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004735static void
4736fix_partition_table_order(void) {
4737 struct pte *pei, *pek;
4738 int i,k;
4739
4740 if (!wrong_p_order(NULL)) {
4741 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4742 return;
4743 }
4744
4745 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4746 /* partition i should have come earlier, move it */
4747 /* We have to move data in the MBR */
4748 struct partition *pi, *pk, *pe, pbuf;
4749 pei = &ptes[i];
4750 pek = &ptes[k];
4751
4752 pe = pei->ext_pointer;
4753 pei->ext_pointer = pek->ext_pointer;
4754 pek->ext_pointer = pe;
4755
4756 pi = pei->part_table;
4757 pk = pek->part_table;
4758
4759 memmove(&pbuf, pi, sizeof(struct partition));
4760 memmove(pi, pk, sizeof(struct partition));
4761 memmove(pk, &pbuf, sizeof(struct partition));
4762
4763 pei->changed = pek->changed = 1;
4764 }
4765
4766 if (i)
4767 fix_chain_of_logicals();
4768
4769 printf("Done.\n");
4770
4771}
4772#endif
4773
4774static void
4775list_table(int xtra) {
4776 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004777 int i, w;
4778
4779#ifdef CONFIG_FEATURE_SUN_LABEL
4780 if (sun_label) {
4781 sun_list_table(xtra);
4782 return;
4783 }
4784#endif
4785
4786#ifdef CONFIG_FEATURE_SGI_LABEL
4787 if (sgi_label) {
4788 sgi_list_table(xtra);
4789 return;
4790 }
4791#endif
4792
4793 list_disk_geometry();
4794
4795#ifdef CONFIG_FEATURE_OSF_LABEL
4796 if (osf_label) {
4797 xbsd_print_disklabel(xtra);
4798 return;
4799 }
4800#endif
4801
4802 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4803 but if the device name ends in a digit, say /dev/foo1,
4804 then the partition is called /dev/foo1p3. */
4805 w = strlen(disk_device);
4806 if (w && isdigit(disk_device[w-1]))
4807 w++;
4808 if (w < 5)
4809 w = 5;
4810
4811 printf(_("%*s Boot Start End Blocks Id System\n"),
4812 w+1, _("Device"));
4813
4814 for (i = 0; i < partitions; i++) {
4815 const struct pte *pe = &ptes[i];
4816
4817 p = pe->part_table;
4818 if (p && !is_cleared_partition(p)) {
4819 unsigned int psects = get_nr_sects(p);
4820 unsigned int pblocks = psects;
4821 unsigned int podd = 0;
4822
4823 if (sector_size < 1024) {
4824 pblocks /= (1024 / sector_size);
4825 podd = psects % (1024 / sector_size);
4826 }
4827 if (sector_size > 1024)
4828 pblocks *= (sector_size / 1024);
4829 printf(
Eric Andersen040f4402003-07-30 08:40:37 +00004830 "%s %c %11lu %11lu %11lu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004831 partname(disk_device, i+1, w+2),
4832/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4833 ? '*' : '?',
Eric Andersen040f4402003-07-30 08:40:37 +00004834/* start */ (unsigned long) cround(get_partition_start(pe)),
4835/* end */ (unsigned long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004836 - (psects ? 1 : 0)),
Eric Andersen040f4402003-07-30 08:40:37 +00004837/* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004838/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004839/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004840 check_consistency(p, i);
4841 }
4842 }
4843
4844 /* Is partition table in disk order? It need not be, but... */
4845 /* partition table entries are not checked for correct order if this
4846 is a sgi, sun or aix labeled disk... */
4847 if (dos_label && wrong_p_order(NULL)) {
4848 printf(_("\nPartition table entries are not in disk order\n"));
4849 }
4850}
4851
4852#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4853static void
4854x_list_table(int extend) {
4855 const struct pte *pe;
4856 const struct partition *p;
4857 int i;
4858
4859 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4860 disk_device, heads, sectors, cylinders);
4861 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4862 for (i = 0 ; i < partitions; i++) {
4863 pe = &ptes[i];
4864 p = (extend ? pe->ext_pointer : pe->part_table);
4865 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004866 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004867 i + 1, p->boot_ind, p->head,
4868 sector(p->sector),
4869 cylinder(p->sector, p->cyl), p->end_head,
4870 sector(p->end_sector),
4871 cylinder(p->end_sector, p->end_cyl),
4872 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4873 if (p->sys_ind)
4874 check_consistency(p, i);
4875 }
4876 }
4877}
4878#endif
4879
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004880#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004881static void
4882fill_bounds(uint *first, uint *last) {
4883 int i;
4884 const struct pte *pe = &ptes[0];
4885 const struct partition *p;
4886
4887 for (i = 0; i < partitions; pe++,i++) {
4888 p = pe->part_table;
4889 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
4890 first[i] = 0xffffffff;
4891 last[i] = 0;
4892 } else {
4893 first[i] = get_partition_start(pe);
4894 last[i] = first[i] + get_nr_sects(p) - 1;
4895 }
4896 }
4897}
4898
4899static void
4900check(int n, uint h, uint s, uint c, uint start) {
4901 uint total, real_s, real_c;
4902
4903 real_s = sector(s) - 1;
4904 real_c = cylinder(s, c);
4905 total = (real_c * sectors + real_s) * heads + h;
4906 if (!total)
4907 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4908 if (h >= heads)
4909 fprintf(stderr,
4910 _("Partition %d: head %d greater than maximum %d\n"),
4911 n, h + 1, heads);
4912 if (real_s >= sectors)
4913 fprintf(stderr, _("Partition %d: sector %d greater than "
4914 "maximum %d\n"), n, s, sectors);
4915 if (real_c >= cylinders)
4916 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
4917 "maximum %d\n"), n, real_c + 1, cylinders);
4918 if (cylinders <= 1024 && start != total)
4919 fprintf(stderr,
4920 _("Partition %d: previous sectors %d disagrees with "
4921 "total %d\n"), n, start, total);
4922}
4923
4924static void
4925verify(void) {
4926 int i, j;
4927 uint total = 1;
4928 uint first[partitions], last[partitions];
4929 struct partition *p;
4930
4931 if (warn_geometry())
4932 return;
4933
4934#ifdef CONFIG_FEATURE_SUN_LABEL
4935 if (sun_label) {
4936 verify_sun();
4937 return;
4938 }
4939#endif
4940#ifdef CONFIG_FEATURE_SGI_LABEL
4941 if (sgi_label) {
4942 verify_sgi(1);
4943 return;
4944 }
4945#endif
4946
4947 fill_bounds(first, last);
4948 for (i = 0; i < partitions; i++) {
4949 struct pte *pe = &ptes[i];
4950
4951 p = pe->part_table;
4952 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
4953 check_consistency(p, i);
4954 if (get_partition_start(pe) < first[i])
4955 printf(_("Warning: bad start-of-data in "
4956 "partition %d\n"), i + 1);
4957 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4958 last[i]);
4959 total += last[i] + 1 - first[i];
4960 for (j = 0; j < i; j++)
4961 if ((first[i] >= first[j] && first[i] <= last[j])
4962 || ((last[i] <= last[j] && last[i] >= first[j]))) {
4963 printf(_("Warning: partition %d overlaps "
4964 "partition %d.\n"), j + 1, i + 1);
4965 total += first[i] >= first[j] ?
4966 first[i] : first[j];
4967 total -= last[i] <= last[j] ?
4968 last[i] : last[j];
4969 }
4970 }
4971 }
4972
4973 if (extended_offset) {
4974 struct pte *pex = &ptes[ext_index];
4975 uint e_last = get_start_sect(pex->part_table) +
4976 get_nr_sects(pex->part_table) - 1;
4977
4978 for (i = 4; i < partitions; i++) {
4979 total++;
4980 p = ptes[i].part_table;
4981 if (!p->sys_ind) {
4982 if (i != 4 || i + 1 < partitions)
4983 printf(_("Warning: partition %d "
4984 "is empty\n"), i + 1);
4985 }
4986 else if (first[i] < extended_offset ||
4987 last[i] > e_last)
4988 printf(_("Logical partition %d not entirely in "
4989 "partition %d\n"), i + 1, ext_index + 1);
4990 }
4991 }
4992
4993 if (total > heads * sectors * cylinders)
4994 printf(_("Total allocated sectors %d greater than the maximum "
4995 "%d\n"), total, heads * sectors * cylinders);
4996 else if ((total = heads * sectors * cylinders - total) != 0)
4997 printf(_("%d unallocated sectors\n"), total);
4998}
4999
5000static void
5001add_partition(int n, int sys) {
5002 char mesg[256]; /* 48 does not suffice in Japanese */
5003 int i, readed = 0;
5004 struct partition *p = ptes[n].part_table;
5005 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005006 long long llimit;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005007 uint start, stop = 0, limit, temp,
5008 first[partitions], last[partitions];
5009
5010 if (p && p->sys_ind) {
5011 printf(_("Partition %d is already defined. Delete "
5012 "it before re-adding it.\n"), n + 1);
5013 return;
5014 }
5015 fill_bounds(first, last);
5016 if (n < 4) {
5017 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005018 if (display_in_cyl_units || !total_number_of_sectors)
5019 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005020 else
Eric Andersen040f4402003-07-30 08:40:37 +00005021 llimit = total_number_of_sectors - 1;
5022 limit = llimit;
5023 if (limit != llimit)
5024 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005025 if (extended_offset) {
5026 first[ext_index] = extended_offset;
5027 last[ext_index] = get_start_sect(q) +
5028 get_nr_sects(q) - 1;
5029 }
5030 } else {
5031 start = extended_offset + sector_offset;
5032 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5033 }
5034 if (display_in_cyl_units)
5035 for (i = 0; i < partitions; i++)
5036 first[i] = (cround(first[i]) - 1) * units_per_sector;
5037
5038 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5039 do {
5040 temp = start;
5041 for (i = 0; i < partitions; i++) {
5042 int lastplusoff;
5043
5044 if (start == ptes[i].offset)
5045 start += sector_offset;
5046 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
5047 if (start >= first[i] && start <= lastplusoff)
5048 start = lastplusoff + 1;
5049 }
5050 if (start > limit)
5051 break;
5052 if (start >= temp+units_per_sector && readed) {
5053 printf(_("Sector %d is already allocated\n"), temp);
5054 temp = start;
5055 readed = 0;
5056 }
5057 if (!readed && start == temp) {
5058 uint saved_start;
5059
5060 saved_start = start;
5061 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5062 0, mesg);
5063 if (display_in_cyl_units) {
5064 start = (start - 1) * units_per_sector;
5065 if (start < saved_start) start = saved_start;
5066 }
5067 readed = 1;
5068 }
5069 } while (start != temp || !readed);
5070 if (n > 4) { /* NOT for fifth partition */
5071 struct pte *pe = &ptes[n];
5072
5073 pe->offset = start - sector_offset;
5074 if (pe->offset == extended_offset) { /* must be corrected */
5075 pe->offset++;
5076 if (sector_offset == 1)
5077 start++;
5078 }
5079 }
5080
5081 for (i = 0; i < partitions; i++) {
5082 struct pte *pe = &ptes[i];
5083
5084 if (start < pe->offset && limit >= pe->offset)
5085 limit = pe->offset - 1;
5086 if (start < first[i] && limit >= first[i])
5087 limit = first[i] - 1;
5088 }
5089 if (start > limit) {
5090 printf(_("No free sectors available\n"));
5091 if (n > 4)
5092 partitions--;
5093 return;
5094 }
5095 if (cround(start) == cround(limit)) {
5096 stop = limit;
5097 } else {
5098 snprintf(mesg, sizeof(mesg),
5099 _("Last %s or +size or +sizeM or +sizeK"),
5100 str_units(SINGULAR));
5101 stop = read_int(cround(start), cround(limit), cround(limit),
5102 cround(start), mesg);
5103 if (display_in_cyl_units) {
5104 stop = stop * units_per_sector - 1;
5105 if (stop >limit)
5106 stop = limit;
5107 }
5108 }
5109
5110 set_partition(n, 0, start, stop, sys);
5111 if (n > 4)
5112 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5113
5114 if (IS_EXTENDED (sys)) {
5115 struct pte *pe4 = &ptes[4];
5116 struct pte *pen = &ptes[n];
5117
5118 ext_index = n;
5119 pen->ext_pointer = p;
5120 pe4->offset = extended_offset = start;
5121 pe4->sectorbuffer = xcalloc(1, sector_size);
5122 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5123 pe4->ext_pointer = pe4->part_table + 1;
5124 pe4->changed = 1;
5125 partitions = 5;
5126 }
5127}
5128
5129static void
5130add_logical(void) {
5131 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5132 struct pte *pe = &ptes[partitions];
5133
5134 pe->sectorbuffer = xcalloc(1, sector_size);
5135 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5136 pe->ext_pointer = pe->part_table + 1;
5137 pe->offset = 0;
5138 pe->changed = 1;
5139 partitions++;
5140 }
5141 add_partition(partitions - 1, LINUX_NATIVE);
5142}
5143
5144static void
5145new_partition(void) {
5146 int i, free_primary = 0;
5147
5148 if (warn_geometry())
5149 return;
5150
5151#ifdef CONFIG_FEATURE_SUN_LABEL
5152 if (sun_label) {
5153 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5154 return;
5155 }
5156#endif
5157#ifdef CONFIG_FEATURE_SGI_LABEL
5158 if (sgi_label) {
5159 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5160 return;
5161 }
5162#endif
5163#ifdef CONFIG_FEATURE_AIX_LABEL
5164 if (aix_label) {
5165 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5166 "\n\tIf you want to add DOS-type partitions, create"
5167 "\n\ta new empty DOS partition table first. (Use o.)"
5168 "\n\tWARNING: "
5169 "This will destroy the present disk contents.\n"));
5170 return;
5171 }
5172#endif
5173
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005174 for (i = 0; i < 4; i++)
5175 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005176
5177 if (!free_primary && partitions >= MAXIMUM_PARTS) {
5178 printf(_("The maximum number of partitions has been created\n"));
5179 return;
5180 }
5181
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005182 if (!free_primary) {
5183 if (extended_offset)
5184 add_logical();
5185 else
5186 printf(_("You must delete some partition and add "
5187 "an extended partition first\n"));
5188 } else {
5189 char c, line[LINE_LENGTH];
5190 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5191 "partition (1-4)\n",
5192 "Command action", (extended_offset ?
5193 "l logical (5 or over)" : "e extended"));
5194 while (1) {
5195 if ((c = read_char(line)) == 'p' || c == 'P') {
5196 i = get_nonexisting_partition(0, 4);
5197 if (i >= 0)
5198 add_partition(i, LINUX_NATIVE);
5199 return;
5200 }
5201 else if (c == 'l' && extended_offset) {
5202 add_logical();
5203 return;
5204 }
5205 else if (c == 'e' && !extended_offset) {
5206 i = get_nonexisting_partition(0, 4);
5207 if (i >= 0)
5208 add_partition(i, EXTENDED);
5209 return;
5210 }
5211 else
5212 printf(_("Invalid partition number "
5213 "for type `%c'\n"), c);
5214 }
5215 }
5216}
5217
5218static void
5219write_table(void) {
5220 int i;
5221
5222 if (dos_label) {
5223 for (i=0; i<3; i++)
5224 if (ptes[i].changed)
5225 ptes[3].changed = 1;
5226 for (i = 3; i < partitions; i++) {
5227 struct pte *pe = &ptes[i];
5228
5229 if (pe->changed) {
5230 write_part_table_flag(pe->sectorbuffer);
5231 write_sector(pe->offset, pe->sectorbuffer);
5232 }
5233 }
5234 }
5235#ifdef CONFIG_FEATURE_SGI_LABEL
5236 else if (sgi_label) {
5237 /* no test on change? the printf below might be mistaken */
5238 sgi_write_table();
5239 }
5240#endif
5241#ifdef CONFIG_FEATURE_SUN_LABEL
5242 else if (sun_label) {
5243 int needw = 0;
5244
5245 for (i=0; i<8; i++)
5246 if (ptes[i].changed)
5247 needw = 1;
5248 if (needw)
5249 sun_write_table();
5250 }
5251#endif
5252
5253 printf(_("The partition table has been altered!\n\n"));
5254 reread_partition_table(1);
5255}
5256
5257void
5258reread_partition_table(int leave) {
5259 int error = 0;
5260 int i;
5261
5262 printf(_("Calling ioctl() to re-read partition table.\n"));
5263 sync();
5264 sleep(2);
5265 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5266 error = errno;
5267 } else {
5268 /* some kernel versions (1.2.x) seem to have trouble
5269 rereading the partition table, but if asked to do it
5270 twice, the second time works. - biro@yggdrasil.com */
5271 sync();
5272 sleep(2);
5273 if ((i = ioctl(fd, BLKRRPART)) != 0)
5274 error = errno;
5275 }
5276
5277 if (i) {
5278 printf(_("\nWARNING: Re-reading the partition table "
5279 "failed with error %d: %s.\n"
5280 "The kernel still uses the old table.\n"
5281 "The new table will be used "
5282 "at the next reboot.\n"),
5283 error, strerror(error));
5284 }
5285
5286 if (dos_changed)
5287 printf(
5288 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5289 "partitions, please see the fdisk manual page for additional\n"
5290 "information.\n"));
5291
5292 if (leave) {
5293 close(fd);
5294
5295 printf(_("Syncing disks.\n"));
5296 sync();
5297 sleep(4); /* for sync() */
5298 exit(!!i);
5299 }
5300}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005301#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005302
5303#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5304#define MAX_PER_LINE 16
5305static void
5306print_buffer(char pbuffer[]) {
5307 int i,
5308 l;
5309
5310 for (i = 0, l = 0; i < sector_size; i++, l++) {
5311 if (l == 0)
5312 printf("0x%03X:", i);
5313 printf(" %02X", (unsigned char) pbuffer[i]);
5314 if (l == MAX_PER_LINE - 1) {
5315 printf("\n");
5316 l = -1;
5317 }
5318 }
5319 if (l > 0)
5320 printf("\n");
5321 printf("\n");
5322}
5323
5324
5325static void
5326print_raw(void) {
5327 int i;
5328
5329 printf(_("Device: %s\n"), disk_device);
5330#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5331 if (sun_label || sgi_label)
5332 print_buffer(MBRbuffer);
5333 else
5334#endif
5335 for (i = 3; i < partitions; i++)
5336 print_buffer(ptes[i].sectorbuffer);
5337}
5338
5339static void
5340move_begin(int i) {
5341 struct pte *pe = &ptes[i];
5342 struct partition *p = pe->part_table;
5343 uint new, first;
5344
5345 if (warn_geometry())
5346 return;
5347 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
5348 printf(_("Partition %d has no data area\n"), i + 1);
5349 return;
5350 }
5351 first = get_partition_start(pe);
5352 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5353 _("New beginning of data")) - pe->offset;
5354
5355 if (new != get_nr_sects(p)) {
5356 first = get_nr_sects(p) + get_start_sect(p) - new;
5357 set_nr_sects(p, first);
5358 set_start_sect(p, new);
5359 pe->changed = 1;
5360 }
5361}
5362
5363static void
5364xselect(void) {
5365 char c;
5366
5367 while(1) {
5368 putchar('\n');
5369 c = tolower(read_char(_("Expert command (m for help): ")));
5370 switch (c) {
5371 case 'a':
5372#ifdef CONFIG_FEATURE_SUN_LABEL
5373 if (sun_label)
5374 sun_set_alt_cyl();
5375#endif
5376 break;
5377 case 'b':
5378 if (dos_label)
5379 move_begin(get_partition(0, partitions));
5380 break;
5381 case 'c':
5382 user_cylinders = cylinders =
5383 read_int(1, cylinders, 1048576, 0,
5384 _("Number of cylinders"));
5385#ifdef CONFIG_FEATURE_SUN_LABEL
5386 if (sun_label)
5387 sun_set_ncyl(cylinders);
5388#endif
5389 if (dos_label)
5390 warn_cylinders();
5391 break;
5392 case 'd':
5393 print_raw();
5394 break;
5395 case 'e':
5396#ifdef CONFIG_FEATURE_SGI_LABEL
5397 if (sgi_label)
5398 sgi_set_xcyl();
5399 else
5400#endif
5401#ifdef CONFIG_FEATURE_SUN_LABEL
5402 if (sun_label)
5403 sun_set_xcyl();
5404 else
5405#endif
5406 if (dos_label)
5407 x_list_table(1);
5408 break;
5409 case 'f':
5410 if (dos_label)
5411 fix_partition_table_order();
5412 break;
5413 case 'g':
5414#ifdef CONFIG_FEATURE_SGI_LABEL
5415 create_sgilabel();
5416#endif
5417 break;
5418 case 'h':
5419 user_heads = heads = read_int(1, heads, 256, 0,
5420 _("Number of heads"));
5421 update_units();
5422 break;
5423 case 'i':
5424#ifdef CONFIG_FEATURE_SUN_LABEL
5425 if (sun_label)
5426 sun_set_ilfact();
5427#endif
5428 break;
5429 case 'o':
5430#ifdef CONFIG_FEATURE_SUN_LABEL
5431 if (sun_label)
5432 sun_set_rspeed();
5433#endif
5434 break;
5435 case 'p':
5436#ifdef CONFIG_FEATURE_SUN_LABEL
5437 if (sun_label)
5438 list_table(1);
5439 else
5440#endif
5441 x_list_table(0);
5442 break;
5443 case 'q':
5444 close(fd);
5445 printf("\n");
5446 exit(0);
5447 case 'r':
5448 return;
5449 case 's':
5450 user_sectors = sectors = read_int(1, sectors, 63, 0,
5451 _("Number of sectors"));
5452 if (dos_compatible_flag) {
5453 sector_offset = sectors;
5454 fprintf(stderr, _("Warning: setting "
5455 "sector offset for DOS "
5456 "compatiblity\n"));
5457 }
5458 update_units();
5459 break;
5460 case 'v':
5461 verify();
5462 break;
5463 case 'w':
5464 write_table(); /* does not return */
5465 break;
5466 case 'y':
5467#ifdef CONFIG_FEATURE_SUN_LABEL
5468 if (sun_label)
5469 sun_set_pcylcount();
5470#endif
5471 break;
5472 default:
5473 xmenu();
5474 }
5475 }
5476}
5477#endif /* ADVANCED mode */
5478
5479static int
5480is_ide_cdrom_or_tape(const char *device) {
5481 FILE *procf;
5482 char buf[100];
5483 struct stat statbuf;
5484 int is_ide = 0;
5485
5486 /* No device was given explicitly, and we are trying some
5487 likely things. But opening /dev/hdc may produce errors like
5488 "hdc: tray open or drive not ready"
5489 if it happens to be a CD-ROM drive. It even happens that
5490 the process hangs on the attempt to read a music CD.
5491 So try to be careful. This only works since 2.1.73. */
5492
5493 if (strncmp("/dev/hd", device, 7))
5494 return 0;
5495
5496 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5497 procf = fopen(buf, "r");
5498 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5499 is_ide = (!strncmp(buf, "cdrom", 5) ||
5500 !strncmp(buf, "tape", 4));
5501 else
5502 /* Now when this proc file does not exist, skip the
5503 device when it is read-only. */
5504 if (stat(device, &statbuf) == 0)
5505 is_ide = ((statbuf.st_mode & 0222) == 0);
5506
5507 if (procf)
5508 fclose(procf);
5509 return is_ide;
5510}
5511
5512static void
5513try(const char *device, int user_specified) {
5514 int gb;
5515
5516 disk_device = device;
5517 if (setjmp(listingbuf))
5518 return;
5519 if (!user_specified)
5520 if (is_ide_cdrom_or_tape(device))
5521 return;
5522 if ((fd = open(disk_device, type_open)) >= 0) {
5523 gb = get_boot(try_only);
5524 if (gb > 0) { /* I/O error */
5525 close(fd);
5526 } else if (gb < 0) { /* no DOS signature */
5527 list_disk_geometry();
5528 if (aix_label)
5529 return;
5530#ifdef CONFIG_FEATURE_OSF_LABEL
5531 if (btrydev(device) < 0)
5532#endif
5533 fprintf(stderr,
5534 _("Disk %s doesn't contain a valid "
5535 "partition table\n"), device);
5536 close(fd);
5537 } else {
5538 close(fd);
5539 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005540#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005541 if (!sun_label && partitions > 4)
5542 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005543#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005544 }
5545 } else {
5546 /* Ignore other errors, since we try IDE
5547 and SCSI hard disks which may not be
5548 installed on the system. */
5549 if (errno == EACCES) {
5550 fprintf(stderr, _("Cannot open %s\n"), device);
5551 return;
5552 }
5553 }
5554}
5555
5556/* for fdisk -l: try all things in /proc/partitions
5557 that look like a partition name (do not end in a digit) */
5558static void
5559tryprocpt(void) {
5560 FILE *procpt;
5561 char line[100], ptname[100], devname[120], *s;
5562 int ma, mi, sz;
5563
Manuel Novoa III cad53642003-03-19 09:13:01 +00005564 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005565
5566 while (fgets(line, sizeof(line), procpt)) {
5567 if (sscanf (line, " %d %d %d %[^\n ]",
5568 &ma, &mi, &sz, ptname) != 4)
5569 continue;
5570 for (s = ptname; *s; s++);
5571 if (isdigit(s[-1]))
5572 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005573 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005574 try(devname, 0);
5575 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005576#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005577 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005578#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005579}
5580
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005581#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005582static void
5583unknown_command(int c) {
5584 printf(_("%c: unknown command\n"), c);
5585}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005586#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005587
5588int fdisk_main(int argc, char **argv) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005589 int c;
5590#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5591 int optl = 0;
5592#endif
5593#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5594 int opts = 0;
5595#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005596 /*
5597 * Calls:
5598 * fdisk -v
5599 * fdisk -l [-b sectorsize] [-u] device ...
5600 * fdisk -s [partition] ...
5601 * fdisk [-b sectorsize] [-u] device
5602 *
5603 * Options -C, -H, -S set the geometry.
5604 *
5605 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005606 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5607#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5608 "s"
5609#endif
5610 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005611 switch (c) {
5612 case 'b':
5613 /* Ugly: this sector size is really per device,
5614 so cannot be combined with multiple disks,
5615 and te same goes for the C/H/S options.
5616 */
5617 sector_size = atoi(optarg);
5618 if (sector_size != 512 && sector_size != 1024 &&
5619 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005620 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005621 sector_offset = 2;
5622 user_set_sector_size = 1;
5623 break;
5624 case 'C':
5625 user_cylinders = atoi(optarg);
5626 break;
5627 case 'H':
5628 user_heads = atoi(optarg);
5629 if (user_heads <= 0 || user_heads >= 256)
5630 user_heads = 0;
5631 break;
5632 case 'S':
5633 user_sectors = atoi(optarg);
5634 if (user_sectors <= 0 || user_sectors >= 64)
5635 user_sectors = 0;
5636 break;
5637 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005638#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005639 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005640#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005641 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005642#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005643 case 's':
5644 opts = 1;
5645 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005646#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005647 case 'u':
5648 display_in_cyl_units = 0;
5649 break;
5650 case 'V':
5651 case 'v':
5652 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5653 return 0;
5654 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005655 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005656 }
5657 }
5658
5659#if 0
5660 printf(_("This kernel finds the sector size itself - "
5661 "-b option ignored\n"));
5662#else
5663 if (user_set_sector_size && argc-optind != 1)
5664 printf(_("Warning: the -b (set sector size) option should"
5665 " be used with one specified device\n"));
5666#endif
5667
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005668#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005669 if (optl) {
5670 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005671#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005672 type_open = O_RDONLY;
5673 if (argc > optind) {
5674 int k;
5675#if __GNUC__
5676 /* avoid gcc warning:
5677 variable `k' might be clobbered by `longjmp' */
5678 (void)&k;
5679#endif
5680 listing = 1;
5681 for (k=optind; k<argc; k++)
5682 try(argv[k], 1);
5683 } else {
5684 /* we no longer have default device names */
5685 /* but, we can use /proc/partitions instead */
5686 tryprocpt();
5687 }
5688 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005689#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005690 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005691#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005692
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005693#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005694 if (opts) {
5695 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005696 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005697
5698 nowarn = 1;
5699 type_open = O_RDONLY;
5700
5701 opts = argc - optind;
5702 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005703 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005704
5705 for (j = optind; j < argc; j++) {
5706 disk_device = argv[j];
5707 if ((fd = open(disk_device, type_open)) < 0)
5708 fdisk_fatal(unable_to_open);
5709 if (ioctl(fd, BLKGETSIZE, &size))
5710 fdisk_fatal(ioctl_error);
5711 close(fd);
5712 if (opts == 1)
5713 printf("%ld\n", size/2);
5714 else
5715 printf("%s: %ld\n", argv[j], size/2);
5716 }
5717 return 0;
5718 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005719#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005720
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005721#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005722 if (argc-optind == 1)
5723 disk_device = argv[optind];
5724 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005725 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005726
5727 get_boot(fdisk);
5728
5729#ifdef CONFIG_FEATURE_OSF_LABEL
5730 if (osf_label) {
5731 /* OSF label, and no DOS label */
5732 printf(_("Detected an OSF/1 disklabel on %s, entering "
5733 "disklabel mode.\n"),
5734 disk_device);
5735 bselect();
5736 osf_label = 0;
5737 /* If we return we may want to make an empty DOS label? */
5738 }
5739#endif
5740
5741 while (1) {
5742 putchar('\n');
5743 c = tolower(read_char(_("Command (m for help): ")));
5744 switch (c) {
5745 case 'a':
5746 if (dos_label)
5747 toggle_active(get_partition(1, partitions));
5748#ifdef CONFIG_FEATURE_SUN_LABEL
5749 else if (sun_label)
5750 toggle_sunflags(get_partition(1, partitions),
5751 0x01);
5752#endif
5753#ifdef CONFIG_FEATURE_SGI_LABEL
5754 else if (sgi_label)
5755 sgi_set_bootpartition(
5756 get_partition(1, partitions));
5757#endif
5758 else
5759 unknown_command(c);
5760 break;
5761 case 'b':
5762#ifdef CONFIG_FEATURE_SGI_LABEL
5763 if (sgi_label) {
5764 printf(_("\nThe current boot file is: %s\n"),
5765 sgi_get_bootfile());
5766 if (read_chars(_("Please enter the name of the "
5767 "new boot file: ")) == '\n')
5768 printf(_("Boot file unchanged\n"));
5769 else
5770 sgi_set_bootfile(line_ptr);
5771 } else
5772#endif
5773#ifdef CONFIG_FEATURE_OSF_LABEL
5774 bselect();
5775#endif
5776 break;
5777 case 'c':
5778 if (dos_label)
5779 toggle_dos_compatibility_flag();
5780#ifdef CONFIG_FEATURE_SUN_LABEL
5781 else if (sun_label)
5782 toggle_sunflags(get_partition(1, partitions),
5783 0x10);
5784#endif
5785#ifdef CONFIG_FEATURE_SGI_LABEL
5786 else if (sgi_label)
5787 sgi_set_swappartition(
5788 get_partition(1, partitions));
5789#endif
5790 else
5791 unknown_command(c);
5792 break;
5793 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005794 {
Eric Andersen040f4402003-07-30 08:40:37 +00005795 int j;
5796#ifdef CONFIG_FEATURE_SGI_LABEL
5797 /* If sgi_label then don't use get_existing_partition,
5798 let the user select a partition, since
5799 get_existing_partition() only works for Linux-like
5800 partition tables */
5801 if (!sgi_label) {
5802 j = get_existing_partition(1, partitions);
5803 } else {
5804 j = get_partition(1, partitions);
5805 }
5806#else
5807 j = get_existing_partition(1, partitions);
5808#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005809 if (j >= 0)
5810 delete_partition(j);
5811 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005812 break;
5813 case 'i':
5814#ifdef CONFIG_FEATURE_SGI_LABEL
5815 if (sgi_label)
5816 create_sgiinfo();
5817 else
5818#endif
5819 unknown_command(c);
5820 case 'l':
5821 list_types(get_sys_types());
5822 break;
5823 case 'm':
5824 menu();
5825 break;
5826 case 'n':
5827 new_partition();
5828 break;
5829 case 'o':
5830 create_doslabel();
5831 break;
5832 case 'p':
5833 list_table(0);
5834 break;
5835 case 'q':
5836 close(fd);
5837 printf("\n");
5838 return 0;
5839 case 's':
5840#ifdef CONFIG_FEATURE_SUN_LABEL
5841 create_sunlabel();
5842#endif
5843 break;
5844 case 't':
5845 change_sysid();
5846 break;
5847 case 'u':
5848 change_units();
5849 break;
5850 case 'v':
5851 verify();
5852 break;
5853 case 'w':
5854 write_table(); /* does not return */
5855 break;
5856#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5857 case 'x':
5858#ifdef CONFIG_FEATURE_SGI_LABEL
5859 if (sgi_label) {
5860 fprintf(stderr,
5861 _("\n\tSorry, no experts menu for SGI "
5862 "partition tables available.\n\n"));
5863 } else
5864#endif
5865
5866 xselect();
5867 break;
5868#endif
5869 default:
5870 unknown_command(c);
5871 menu();
5872 }
5873 }
5874 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005875#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005876}