blob: eb26abb59f572dac1dbb2a99ec501bf1b94fad41 [file] [log] [blame]
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
4 *
5 * This program is free software. You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation: either version 1 or
8 * (at your option) any later version.
9 *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000010 * Vladimir Oleynik <dzo@simtreas.ru> 2001,2002 Busybox port
11 */
12
Eric Andersen99a75d12003-08-08 20:04:56 +000013#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014
15#define PROC_PARTITIONS "/proc/partitions"
16
Eric Andersen256c4fd2004-05-19 09:00:00 +000017#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000018#include <sys/types.h>
19#include <sys/stat.h> /* stat */
20#include <ctype.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <errno.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <setjmp.h>
28#include <assert.h> /* assert */
29#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000031#include <sys/ioctl.h>
32#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000033#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000034
Eric Andersenacd244a2002-12-11 03:49:33 +000035#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
36
37/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000038#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000039
40#include <sys/utsname.h>
41
42#include "busybox.h"
43
44#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
45
46#define DKTYPENAMES
47
48#define _(Text) Text
49
50#define BLKRRPART _IO(0x12,95) /* re-read partition table */
51#define BLKGETSIZE _IO(0x12,96) /* return device size */
52#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
53#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000054
55/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000056 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000057#undef _IOR
58#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000059#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000060
61/*
62 fdisk.h
63*/
64
65#define DEFAULT_SECTOR_SIZE 512
66#define MAX_SECTOR_SIZE 2048
67#define SECTOR_SIZE 512 /* still used in BSD code */
68#define MAXIMUM_PARTS 60
69
70#define ACTIVE_FLAG 0x80
71
72#define EXTENDED 0x05
73#define WIN98_EXTENDED 0x0f
74#define LINUX_PARTITION 0x81
75#define LINUX_SWAP 0x82
76#define LINUX_NATIVE 0x83
77#define LINUX_EXTENDED 0x85
78#define LINUX_LVM 0x8e
79#define LINUX_RAID 0xfd
80
81#define SUNOS_SWAP 3
82#define WHOLE_DISK 5
83
84#define IS_EXTENDED(i) \
85 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
86
87#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
88
89#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
90#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
91
Eric Andersen7495b0d2004-02-06 05:26:58 +000092#ifdef CONFIG_FEATURE_SUN_LABEL
93#define SCSI_IOCTL_GET_IDLUN 0x5382
94#endif
95
Eric Andersend3652bf2003-08-06 09:07:37 +000096
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000097/* 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 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000120#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000121static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000122#else
123# define MBRbuffer bb_common_bufsiz1
124#endif
125
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000126#ifdef CONFIG_FEATURE_SUN_LABEL
127static int sun_label; /* looking at sun disklabel */
128#else
129#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000130#endif
131#ifdef CONFIG_FEATURE_SGI_LABEL
132static int sgi_label; /* looking at sgi disklabel */
133#else
134#define sgi_label 0
135#endif
136#ifdef CONFIG_FEATURE_AIX_LABEL
137static int aix_label; /* looking at aix disklabel */
138#else
139#define aix_label 0
140#endif
141#ifdef CONFIG_FEATURE_OSF_LABEL
142static int osf_label; /* looking at OSF/1 disklabel */
143static int possibly_osf_label;
144#else
145#define osf_label 0
146#endif
147
148#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
149
150static uint heads, sectors, cylinders;
151static void update_units(void);
152
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000153
154/*
155 * return partition name - uses static storage unless buf is supplied
156 */
157static const char *
158partname(const char *dev, int pno, int lth) {
159 static char buffer[80];
160 const char *p;
161 int w, wp;
162 int bufsiz;
163 char *bufp;
164
165 bufp = buffer;
166 bufsiz = sizeof(buffer);
167
168 w = strlen(dev);
169 p = "";
170
171 if (isdigit(dev[w-1]))
172 p = "p";
173
174 /* devfs kludge - note: fdisk partition names are not supposed
175 to equal kernel names, so there is no reason to do this */
176 if (strcmp (dev + w - 4, "disc") == 0) {
177 w -= 4;
178 p = "part";
179 }
180
181 wp = strlen(p);
182
183 if (lth) {
184 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
185 lth-wp-2, w, dev, p, pno);
186 } else {
187 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
188 }
189 return bufp;
190}
191
192struct partition {
193 unsigned char boot_ind; /* 0x80 - active */
194 unsigned char head; /* starting head */
195 unsigned char sector; /* starting sector */
196 unsigned char cyl; /* starting cylinder */
197 unsigned char sys_ind; /* What partition type */
198 unsigned char end_head; /* end head */
199 unsigned char end_sector; /* end sector */
200 unsigned char end_cyl; /* end cylinder */
201 unsigned char start4[4]; /* starting sector counting from 0 */
202 unsigned char size4[4]; /* nr of sectors in partition */
Eric Andersen7495b0d2004-02-06 05:26:58 +0000203} __attribute__((__packed__));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000204
205enum failure {
206 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
207 unable_to_write
208};
209
210enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
211
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000212static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000213static int fd; /* the disk */
214static int partitions = 4; /* maximum partition + 1 */
215static uint display_in_cyl_units = 1;
216static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000217#ifdef CONFIG_FEATURE_FDISK_WRITABLE
218static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000219static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000220static void reread_partition_table(int leave);
221static void delete_partition(int i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000222static int get_partition(int warn, int max);
223static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000224static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000225#endif
226static const char *partition_type(unsigned char type);
227static void fdisk_fatal(enum failure why) __attribute__ ((noreturn));
228static void get_geometry(void);
229static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000230
231#define PLURAL 0
232#define SINGULAR 1
233
234#define hex_val(c) ({ \
235 char _c = (c); \
236 isdigit(_c) ? _c - '0' : \
237 tolower(_c) + 10 - 'a'; \
238 })
239
240
241#define LINE_LENGTH 800
242#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
243 (n) * sizeof(struct partition)))
244#define sector(s) ((s) & 0x3f)
245#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
246
247#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
248 ((h) + heads * cylinder(s,c)))
249#define set_hsc(h,s,c,sector) { \
250 s = sector % sectors + 1; \
251 sector /= sectors; \
252 h = sector % heads; \
253 sector /= heads; \
254 c = sector & 0xff; \
255 s |= (sector >> 2) & 0xc0; \
256 }
257
258
Eric Andersend9261492004-06-28 23:50:31 +0000259static int32_t get_start_sect(const struct partition *p);
260static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000261
262/*
263 * per partition table entry data
264 *
265 * The four primary partitions have the same sectorbuffer (MBRbuffer)
266 * and have NULL ext_pointer.
267 * Each logical partition table entry has two pointers, one for the
268 * partition and one link to the next one.
269 */
270static struct pte {
271 struct partition *part_table; /* points into sectorbuffer */
272 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000273#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000274 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000275#endif
Eric Andersend9261492004-06-28 23:50:31 +0000276 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000277 char *sectorbuffer; /* disk sector contents */
278} ptes[MAXIMUM_PARTS];
279
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000280
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000281#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000282static void
283set_all_unchanged(void) {
284 int i;
285
286 for (i = 0; i < MAXIMUM_PARTS; i++)
287 ptes[i].changed = 0;
288}
289
290static void
291set_changed(int i) {
292 ptes[i].changed = 1;
293}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000294#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000295
296#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
297static struct partition *
298get_part_table(int i) {
299 return ptes[i].part_table;
300}
301#endif
302
303static const char *
304str_units(int n) { /* n==1: use singular */
305 if (n == 1)
306 return display_in_cyl_units ? _("cylinder") : _("sector");
307 else
308 return display_in_cyl_units ? _("cylinders") : _("sectors");
309}
310
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000311static int
312valid_part_table_flag(const unsigned char *b) {
313 return (b[510] == 0x55 && b[511] == 0xaa);
314}
315
316#ifdef CONFIG_FEATURE_FDISK_WRITABLE
317static char line_buffer[LINE_LENGTH];
318
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000319/* read line; return 0 or first char */
320static int
321read_line(void)
322{
323 static int got_eof = 0;
324
325 fflush (stdout); /* requested by niles@scyld.com */
326 line_ptr = line_buffer;
327 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
328 if (feof(stdin))
329 got_eof++; /* user typed ^D ? */
330 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000331 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
332 exit(1);
333 }
334 return 0;
335 }
336 while (*line_ptr && !isgraph(*line_ptr))
337 line_ptr++;
338 return *line_ptr;
339}
340
341static char
342read_char(const char *mesg)
343{
344 do {
345 fputs(mesg, stdout);
346 } while (!read_line());
347 return *line_ptr;
348}
349
350static char
351read_chars(const char *mesg)
352{
353 fputs(mesg, stdout);
354 if (!read_line()) {
355 *line_ptr = '\n';
356 line_ptr[1] = 0;
357 }
358 return *line_ptr;
359}
360
361static int
362read_hex(const struct systypes *sys)
363{
364 int hex;
365
366 while (1)
367 {
368 read_char(_("Hex code (type L to list codes): "));
369 if (*line_ptr == 'l' || *line_ptr == 'L')
370 list_types(sys);
371 else if (isxdigit (*line_ptr))
372 {
373 hex = 0;
374 do
375 hex = hex << 4 | hex_val(*line_ptr++);
376 while (isxdigit(*line_ptr));
377 return hex;
378 }
379 }
380}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000381#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000382
383#ifdef CONFIG_FEATURE_AIX_LABEL
384/*
385 * Copyright (C) Andreas Neuper, Sep 1998.
386 * This file may be redistributed under
387 * the terms of the GNU Public License.
388 */
389
390typedef struct {
391 unsigned int magic; /* expect AIX_LABEL_MAGIC */
392 unsigned int fillbytes1[124];
393 unsigned int physical_volume_id;
394 unsigned int fillbytes2[124];
395} aix_partition;
396
397#define AIX_LABEL_MAGIC 0xc9c2d4c1
398#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
399#define AIX_INFO_MAGIC 0x00072959
400#define AIX_INFO_MAGIC_SWAPPED 0x59290700
401
402#define aixlabel ((aix_partition *)MBRbuffer)
403
404
405/*
406 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000407 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
408 * Internationalization
409 *
410 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
411 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000412*/
413
414static int aix_other_endian;
415static short aix_volumes=1;
416
417/*
418 * only dealing with free blocks here
419 */
420
421static void
422aix_info( void ) {
423 puts(
424 _("\n\tThere is a valid AIX label on this disk.\n"
425 "\tUnfortunately Linux cannot handle these\n"
426 "\tdisks at the moment. Nevertheless some\n"
427 "\tadvice:\n"
428 "\t1. fdisk will destroy its contents on write.\n"
429 "\t2. Be sure that this disk is NOT a still vital\n"
430 "\t part of a volume group. (Otherwise you may\n"
431 "\t erase the other disks as well, if unmirrored.)\n"
432 "\t3. Before deleting this physical volume be sure\n"
433 "\t to remove the disk logically from your AIX\n"
434 "\t machine. (Otherwise you become an AIXpert).")
435 );
436}
437
438static void
439aix_nolabel( void )
440{
441 aixlabel->magic = 0;
442 aix_label = 0;
443 partitions = 4;
444 memset( MBRbuffer, 0, sizeof(MBRbuffer) ); /* avoid fdisk cores */
445 return;
446}
447
448static int
449check_aix_label( void )
450{
451 if (aixlabel->magic != AIX_LABEL_MAGIC &&
452 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
453 aix_label = 0;
454 aix_other_endian = 0;
455 return 0;
456 }
457 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
458 update_units();
459 aix_label = 1;
460 partitions= 1016;
461 aix_volumes = 15;
462 aix_info();
463 aix_nolabel(); /* %% */
464 aix_label = 1; /* %% */
465 return 1;
466}
467#endif /* AIX_LABEL */
468
469#ifdef CONFIG_FEATURE_OSF_LABEL
470/*
471 * Copyright (c) 1987, 1988 Regents of the University of California.
472 * All rights reserved.
473 *
474 * Redistribution and use in source and binary forms, with or without
475 * modification, are permitted provided that the following conditions
476 * are met:
477 * 1. Redistributions of source code must retain the above copyright
478 * notice, this list of conditions and the following disclaimer.
479 * 2. Redistributions in binary form must reproduce the above copyright
480 * notice, this list of conditions and the following disclaimer in the
481 * documentation and/or other materials provided with the distribution.
482 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000483 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000484 * This product includes software developed by the University of
485 * California, Berkeley and its contributors.
486 * 4. Neither the name of the University nor the names of its contributors
487 * may be used to endorse or promote products derived from this software
488 * without specific prior written permission.
489 *
490 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
491 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
492 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
493 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
494 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
495 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
496 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
497 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
498 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
499 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
500 * SUCH DAMAGE.
501 */
502
503
504#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000505#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000506#endif
507
508#ifndef BSD_MAXPARTITIONS
509#define BSD_MAXPARTITIONS 16
510#endif
511
512#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
513
514#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
515#define BSD_LABELSECTOR 1
516#define BSD_LABELOFFSET 0
517#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
518#define BSD_LABELSECTOR 0
519#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000520#elif defined (__s390__) || defined (__s390x__)
521#define BSD_LABELSECTOR 1
522#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000523#else
524#error unknown architecture
525#endif
526
527#define BSD_BBSIZE 8192 /* size of boot area, with label */
528#define BSD_SBSIZE 8192 /* max size of fs superblock */
529
530struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000531 uint32_t d_magic; /* the magic number */
532 int16_t d_type; /* drive type */
533 int16_t d_subtype; /* controller/d_type specific */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000534 char d_typename[16]; /* type name, e.g. "eagle" */
535 char d_packname[16]; /* pack identifier */
536 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000537 uint32_t d_secsize; /* # of bytes per sector */
538 uint32_t d_nsectors; /* # of data sectors per track */
539 uint32_t d_ntracks; /* # of tracks per cylinder */
540 uint32_t d_ncylinders; /* # of data cylinders per unit */
541 uint32_t d_secpercyl; /* # of data sectors per cylinder */
542 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000543 /*
544 * Spares (bad sector replacements) below
545 * are not counted in d_nsectors or d_secpercyl.
546 * Spare sectors are assumed to be physical sectors
547 * which occupy space at the end of each track and/or cylinder.
548 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000549 uint16_t d_sparespertrack; /* # of spare sectors per track */
550 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000551 /*
552 * Alternate cylinders include maintenance, replacement,
553 * configuration description areas, etc.
554 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000555 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000556
557 /* hardware characteristics: */
558 /*
559 * d_interleave, d_trackskew and d_cylskew describe perturbations
560 * in the media format used to compensate for a slow controller.
561 * Interleave is physical sector interleave, set up by the formatter
562 * or controller when formatting. When interleaving is in use,
563 * logically adjacent sectors are not physically contiguous,
564 * but instead are separated by some number of sectors.
565 * It is specified as the ratio of physical sectors traversed
566 * per logical sector. Thus an interleave of 1:1 implies contiguous
567 * layout, while 2:1 implies that logical sector 0 is separated
568 * by one sector from logical sector 1.
569 * d_trackskew is the offset of sector 0 on track N
570 * relative to sector 0 on track N-1 on the same cylinder.
571 * Finally, d_cylskew is the offset of sector 0 on cylinder N
572 * relative to sector 0 on cylinder N-1.
573 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000574 uint16_t d_rpm; /* rotational speed */
575 uint16_t d_interleave; /* hardware sector interleave */
576 uint16_t d_trackskew; /* sector 0 skew, per track */
577 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
578 uint32_t d_headswitch; /* head switch time, usec */
579 uint32_t d_trkseek; /* track-to-track seek, usec */
580 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000581#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000582 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000583#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000584 uint32_t d_spare[NSPARE]; /* reserved for future use */
585 uint32_t d_magic2; /* the magic number (again) */
586 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000587 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000588 uint16_t d_npartitions; /* number of partitions in following */
589 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
590 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000591 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000592 uint32_t p_size; /* number of sectors in partition */
593 uint32_t p_offset; /* starting sector */
594 uint32_t p_fsize; /* filesystem basic fragment size */
595 uint8_t p_fstype; /* filesystem type, see below */
596 uint8_t p_frag; /* filesystem fragments per block */
597 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000598 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
599};
600
601/* d_type values: */
602#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
603#define BSD_DTYPE_MSCP 2 /* MSCP */
604#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
605#define BSD_DTYPE_SCSI 4 /* SCSI */
606#define BSD_DTYPE_ESDI 5 /* ESDI interface */
607#define BSD_DTYPE_ST506 6 /* ST506 etc. */
608#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
609#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
610#define BSD_DTYPE_FLOPPY 10 /* floppy */
611
612/* d_subtype values: */
613#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
614#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
615#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
616
617#ifdef DKTYPENAMES
618static const char * const xbsd_dktypenames[] = {
619 "unknown",
620 "SMD",
621 "MSCP",
622 "old DEC",
623 "SCSI",
624 "ESDI",
625 "ST506",
626 "HP-IB",
627 "HP-FL",
628 "type 9",
629 "floppy",
630 0
631};
632#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
633#endif
634
635/*
636 * Filesystem type and version.
637 * Used to interpret other filesystem-specific
638 * per-partition information.
639 */
640#define BSD_FS_UNUSED 0 /* unused */
641#define BSD_FS_SWAP 1 /* swap */
642#define BSD_FS_V6 2 /* Sixth Edition */
643#define BSD_FS_V7 3 /* Seventh Edition */
644#define BSD_FS_SYSV 4 /* System V */
645#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
646#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
647#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
648#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
649#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
650#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
651#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
652#define BSD_FS_ISOFS BSD_FS_ISO9660
653#define BSD_FS_BOOT 13 /* partition contains bootstrap */
654#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
655#define BSD_FS_HFS 15 /* Macintosh HFS */
656#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
657
658/* this is annoying, but it's also the way it is :-( */
659#ifdef __alpha__
660#define BSD_FS_EXT2 8 /* ext2 file system */
661#else
662#define BSD_FS_MSDOS 8 /* MS-DOS file system */
663#endif
664
665#ifdef DKTYPENAMES
666static const struct systypes xbsd_fstypes[] = {
667/* BSD_FS_UNUSED */ {"\x00" "unused"},
668/* BSD_FS_SWAP */ {"\x01" "swap"},
669/* BSD_FS_V6 */ {"\x02" "Version 6"},
670/* BSD_FS_V7 */ {"\x03" "Version 7"},
671/* BSD_FS_SYSV */ {"\x04" "System V"},
672/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
673/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
674/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
675#ifdef __alpha__
676/* BSD_FS_EXT2 */ {"\x08" "ext2"},
677#else
678/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
679#endif
680/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
681/* BSD_FS_OTHER */ {"\x0a" "unknown"},
682/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
683/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
684/* BSD_FS_BOOT */ {"\x0d" "boot"},
685/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
686/* BSD_FS_HFS */ {"\x0f" "HFS"},
687/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
688 { NULL }
689};
690#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
691
692#endif
693
694/*
695 * flags shared by various drives:
696 */
697#define BSD_D_REMOVABLE 0x01 /* removable media */
698#define BSD_D_ECC 0x02 /* supports ECC */
699#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
700#define BSD_D_RAMDISK 0x08 /* disk emulator */
701#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
702#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
703
704#endif /* OSF_LABEL */
705
706/*
707 * Copyright (C) Andreas Neuper, Sep 1998.
708 * This file may be modified and redistributed under
709 * the terms of the GNU Public License.
710 */
711
712struct device_parameter { /* 48 bytes */
713 unsigned char skew;
714 unsigned char gap1;
715 unsigned char gap2;
716 unsigned char sparecyl;
717 unsigned short pcylcount;
718 unsigned short head_vol0;
719 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
720 unsigned char cmd_tag_queue_depth;
721 unsigned char unused0;
722 unsigned short unused1;
723 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
724 unsigned short bytes;
725 unsigned short ilfact;
726 unsigned int flags; /* controller flags */
727 unsigned int datarate;
728 unsigned int retries_on_error;
729 unsigned int ms_per_word;
730 unsigned short xylogics_gap1;
731 unsigned short xylogics_syncdelay;
732 unsigned short xylogics_readdelay;
733 unsigned short xylogics_gap2;
734 unsigned short xylogics_readgate;
735 unsigned short xylogics_writecont;
736};
737
738#define SGI_VOLHDR 0x00
739/* 1 and 2 were used for drive types no longer supported by SGI */
740#define SGI_SWAP 0x03
741/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
742#define SGI_VOLUME 0x06
743#define SGI_EFS 0x07
744#define SGI_LVOL 0x08
745#define SGI_RLVOL 0x09
746#define SGI_XFS 0x0a
747#define SGI_XFSLOG 0x0b
748#define SGI_XLV 0x0c
749#define SGI_XVM 0x0d
750#define ENTIRE_DISK SGI_VOLUME
751/*
752 * controller flags
753 */
754#define SECTOR_SLIP 0x01
755#define SECTOR_FWD 0x02
756#define TRACK_FWD 0x04
757#define TRACK_MULTIVOL 0x08
758#define IGNORE_ERRORS 0x10
759#define RESEEK 0x20
760#define ENABLE_CMDTAGQ 0x40
761
762typedef struct {
763 unsigned int magic; /* expect SGI_LABEL_MAGIC */
764 unsigned short boot_part; /* active boot partition */
765 unsigned short swap_part; /* active swap partition */
766 unsigned char boot_file[16]; /* name of the bootfile */
767 struct device_parameter devparam; /* 1 * 48 bytes */
768 struct volume_directory { /* 15 * 16 bytes */
769 unsigned char vol_file_name[8]; /* a character array */
770 unsigned int vol_file_start; /* number of logical block */
771 unsigned int vol_file_size; /* number of bytes */
772 } directory[15];
773 struct sgi_partition { /* 16 * 12 bytes */
774 unsigned int num_sectors; /* number of blocks */
775 unsigned int start_sector; /* must be cylinder aligned */
776 unsigned int id;
777 } partitions[16];
778 unsigned int csum;
779 unsigned int fillbytes;
780} sgi_partition;
781
782typedef struct {
783 unsigned int magic; /* looks like a magic number */
784 unsigned int a2;
785 unsigned int a3;
786 unsigned int a4;
787 unsigned int b1;
788 unsigned short b2;
789 unsigned short b3;
790 unsigned int c[16];
791 unsigned short d[3];
792 unsigned char scsi_string[50];
793 unsigned char serial[137];
794 unsigned short check1816;
795 unsigned char installer[225];
796} sgiinfo;
797
798#define SGI_LABEL_MAGIC 0x0be5a941
799#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
800#define SGI_INFO_MAGIC 0x00072959
801#define SGI_INFO_MAGIC_SWAPPED 0x59290700
802#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000803 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000804#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000805 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000806
807#define sgilabel ((sgi_partition *)MBRbuffer)
808#define sgiparam (sgilabel->devparam)
809
810typedef struct {
811 unsigned char info[128]; /* Informative text string */
812 unsigned char spare0[14];
813 struct sun_info {
814 unsigned char spare1;
815 unsigned char id;
816 unsigned char spare2;
817 unsigned char flags;
818 } infos[8];
819 unsigned char spare1[246]; /* Boot information etc. */
820 unsigned short rspeed; /* Disk rotational speed */
821 unsigned short pcylcount; /* Physical cylinder count */
822 unsigned short sparecyl; /* extra sects per cylinder */
823 unsigned char spare2[4]; /* More magic... */
824 unsigned short ilfact; /* Interleave factor */
825 unsigned short ncyl; /* Data cylinder count */
826 unsigned short nacyl; /* Alt. cylinder count */
827 unsigned short ntrks; /* Tracks per cylinder */
828 unsigned short nsect; /* Sectors per track */
829 unsigned char spare3[4]; /* Even more magic... */
830 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000831 uint32_t start_cylinder;
832 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000833 } partitions[8];
834 unsigned short magic; /* Magic number */
835 unsigned short csum; /* Label xor'd checksum */
836} sun_partition;
837
Eric Andersen040f4402003-07-30 08:40:37 +0000838
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000839#define SUN_LABEL_MAGIC 0xDABE
840#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
841#define sunlabel ((sun_partition *)MBRbuffer)
842#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000843 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000844#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000845 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000846
Eric Andersend3652bf2003-08-06 09:07:37 +0000847
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000848#ifdef CONFIG_FEATURE_OSF_LABEL
849/*
850 Changes:
851 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
852
853 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
854 support for OSF/1 disklabels on Alpha.
855 Also fixed unaligned accesses in alpha_bootblock_checksum()
856*/
857
858#define FREEBSD_PARTITION 0xa5
859#define NETBSD_PARTITION 0xa9
860
861static void xbsd_delete_part (void);
862static void xbsd_new_part (void);
863static void xbsd_write_disklabel (void);
864static int xbsd_create_disklabel (void);
865static void xbsd_edit_disklabel (void);
866static void xbsd_write_bootstrap (void);
867static void xbsd_change_fstype (void);
868static int xbsd_get_part_index (int max);
869static int xbsd_check_new_partition (int *i);
870static void xbsd_list_types (void);
871static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
872static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d,
873 int pindex);
874static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
875static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
876
877#if defined (__alpha__)
878static void alpha_bootblock_checksum (char *boot);
879#endif
880
881#if !defined (__alpha__)
882static int xbsd_translate_fstype (int linux_type);
883static void xbsd_link_part (void);
884static struct partition *xbsd_part;
885static int xbsd_part_index;
886#endif
887
888#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000889/* We access this through a uint64_t * when checksumming */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000890static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
891#else
892static char disklabelbuffer[BSD_BBSIZE];
893#endif
894
895static struct xbsd_disklabel xbsd_dlabel;
896
897#define bsd_cround(n) \
898 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
899
900/*
901 * Test whether the whole disk has BSD disk label magic.
902 *
903 * Note: often reformatting with DOS-type label leaves the BSD magic,
904 * so this does not mean that there is a BSD disk label.
905 */
906static int
907check_osf_label(void) {
908 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
909 return 0;
910 return 1;
911}
912
913static void xbsd_print_disklabel(int);
914
915static int
Glenn L McGrath35631a62002-12-08 11:51:05 +0000916btrydev (const char * dev) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000917 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
918 return -1;
919 printf(_("\nBSD label for device: %s\n"), dev);
920 xbsd_print_disklabel (0);
921 return 0;
922}
923
924static void
925bmenu (void) {
926 puts (_("Command action"));
927 puts (_("\td\tdelete a BSD partition"));
928 puts (_("\te\tedit drive data"));
929 puts (_("\ti\tinstall bootstrap"));
930 puts (_("\tl\tlist known filesystem types"));
931 puts (_("\tm\tprint this menu"));
932 puts (_("\tn\tadd a new BSD partition"));
933 puts (_("\tp\tprint BSD partition table"));
934 puts (_("\tq\tquit without saving changes"));
935 puts (_("\tr\treturn to main menu"));
936 puts (_("\ts\tshow complete disklabel"));
937 puts (_("\tt\tchange a partition's filesystem id"));
938 puts (_("\tu\tchange units (cylinders/sectors)"));
939 puts (_("\tw\twrite disklabel to disk"));
940#if !defined (__alpha__)
941 puts (_("\tx\tlink BSD partition to non-BSD partition"));
942#endif
943}
944
945#if !defined (__alpha__)
946static int
947hidden(int type) {
948 return type ^ 0x10;
949}
950
951static int
952is_bsd_partition_type(int type) {
953 return (type == FREEBSD_PARTITION ||
954 type == hidden(FREEBSD_PARTITION) ||
955 type == NETBSD_PARTITION ||
956 type == hidden(NETBSD_PARTITION));
957}
958#endif
959
960static void
961bselect (void) {
962#if !defined (__alpha__)
963 int t, ss;
964 struct partition *p;
965
966 for (t=0; t<4; t++) {
967 p = get_part_table(t);
968 if (p && is_bsd_partition_type(p->sys_ind)) {
969 xbsd_part = p;
970 xbsd_part_index = t;
971 ss = get_start_sect(xbsd_part);
972 if (ss == 0) {
973 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
974 partname(disk_device, t+1, 0));
975 return;
976 }
977 printf (_("Reading disklabel of %s at sector %d.\n"),
978 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
979 if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
980 if (xbsd_create_disklabel () == 0)
981 return;
982 break;
983 }
984 }
985
986 if (t == 4) {
987 printf (_("There is no *BSD partition on %s.\n"), disk_device);
988 return;
989 }
990
991#elif defined (__alpha__)
992
993 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
994 if (xbsd_create_disklabel () == 0)
995 exit ( EXIT_SUCCESS );
996
997#endif
998
999 while (1) {
1000 putchar ('\n');
1001 switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
1002 case 'd':
1003 xbsd_delete_part ();
1004 break;
1005 case 'e':
1006 xbsd_edit_disklabel ();
1007 break;
1008 case 'i':
1009 xbsd_write_bootstrap ();
1010 break;
1011 case 'l':
1012 xbsd_list_types ();
1013 break;
1014 case 'n':
1015 xbsd_new_part ();
1016 break;
1017 case 'p':
1018 xbsd_print_disklabel (0);
1019 break;
1020 case 'q':
1021 close (fd);
1022 exit ( EXIT_SUCCESS );
1023 case 'r':
1024 return;
1025 case 's':
1026 xbsd_print_disklabel (1);
1027 break;
1028 case 't':
1029 xbsd_change_fstype ();
1030 break;
1031 case 'u':
1032 change_units();
1033 break;
1034 case 'w':
1035 xbsd_write_disklabel ();
1036 break;
1037#if !defined (__alpha__)
1038 case 'x':
1039 xbsd_link_part ();
1040 break;
1041#endif
1042 default:
1043 bmenu ();
1044 break;
1045 }
1046 }
1047}
1048
1049static void
1050xbsd_delete_part (void)
1051{
1052 int i;
1053
1054 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1055 xbsd_dlabel.d_partitions[i].p_size = 0;
1056 xbsd_dlabel.d_partitions[i].p_offset = 0;
1057 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1058 if (xbsd_dlabel.d_npartitions == i + 1)
1059 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1060 xbsd_dlabel.d_npartitions--;
1061}
1062
1063static void
1064xbsd_new_part (void)
1065{
Eric Andersend9261492004-06-28 23:50:31 +00001066 off_t begin, end;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001067 char mesg[256];
1068 int i;
1069
1070 if (!xbsd_check_new_partition (&i))
1071 return;
1072
1073#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1074 begin = get_start_sect(xbsd_part);
1075 end = begin + get_nr_sects(xbsd_part) - 1;
1076#else
1077 begin = 0;
1078 end = xbsd_dlabel.d_secperunit - 1;
1079#endif
1080
1081 snprintf (mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1082 begin = read_int (bsd_cround (begin), bsd_cround (begin), bsd_cround (end),
1083 0, mesg);
1084
1085 if (display_in_cyl_units)
1086 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
1087
1088 snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1089 str_units(SINGULAR));
1090 end = read_int (bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1091 bsd_cround (begin), mesg);
1092
1093 if (display_in_cyl_units)
1094 end = end * xbsd_dlabel.d_secpercyl - 1;
1095
1096 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1097 xbsd_dlabel.d_partitions[i].p_offset = begin;
1098 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1099}
1100
1101static void
1102xbsd_print_disklabel (int show_all) {
1103 struct xbsd_disklabel *lp = &xbsd_dlabel;
1104 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001105 int i, j;
1106
1107 if (show_all) {
1108#if defined (__alpha__)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001109 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001110#else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001111 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001112#endif
1113 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001114 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001115 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001116 printf(_("type: %d\n"), lp->d_type);
1117 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1118 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1119 printf(_("flags:"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001120 if (lp->d_flags & BSD_D_REMOVABLE)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001121 printf(_(" removable"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001122 if (lp->d_flags & BSD_D_ECC)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001123 printf(_(" ecc"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001124 if (lp->d_flags & BSD_D_BADSECT)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001125 printf(_(" badsect"));
1126 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001127 /* On various machines the fields of *lp are short/int/long */
1128 /* In order to avoid problems, we cast them all to long. */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001129 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1130 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1131 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1132 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1133 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1134 printf(_("rpm: %d\n"), lp->d_rpm);
1135 printf(_("interleave: %d\n"), lp->d_interleave);
1136 printf(_("trackskew: %d\n"), lp->d_trackskew);
1137 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1138 printf(_("headswitch: %ld\t\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001139 (long) lp->d_headswitch);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001140 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001141 (long) lp->d_trkseek);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001142 printf(_("drivedata: "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001143 for (i = NDDATA - 1; i >= 0; i--)
1144 if (lp->d_drivedata[i])
1145 break;
1146 if (i < 0)
1147 i = 0;
1148 for (j = 0; j <= i; j++)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001149 printf("%ld ", (long) lp->d_drivedata[j]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001150 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001151 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1152 printf(_("# start end size fstype [fsize bsize cpg]\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001153 pp = lp->d_partitions;
1154 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1155 if (pp->p_size) {
1156 if (display_in_cyl_units && lp->d_secpercyl) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001157 printf(" %c: %8ld%c %8ld%c %8ld%c ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001158 'a' + i,
1159 (long) pp->p_offset / lp->d_secpercyl + 1,
1160 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1161 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
1162 / lp->d_secpercyl,
1163 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1164 (long) pp->p_size / lp->d_secpercyl,
1165 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
1166 } else {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001167 printf(" %c: %8ld %8ld %8ld ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001168 'a' + i,
1169 (long) pp->p_offset,
1170 (long) pp->p_offset + pp->p_size - 1,
1171 (long) pp->p_size);
1172 }
1173 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001174 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001175 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001176 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001177 switch (pp->p_fstype) {
1178 case BSD_FS_UNUSED:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001179 printf(" %5ld %5ld %5.5s ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001180 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1181 break;
1182
1183 case BSD_FS_BSDFFS:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001184 printf(" %5ld %5ld %5d ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001185 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
1186 pp->p_cpg);
1187 break;
1188
1189 default:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001190 printf("%22.22s", "");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001191 break;
1192 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001193 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001194 }
1195 }
1196}
1197
1198static void
1199xbsd_write_disklabel (void) {
1200#if defined (__alpha__)
1201 printf (_("Writing disklabel to %s.\n"), disk_device);
1202 xbsd_writelabel (NULL, &xbsd_dlabel);
1203#else
1204 printf (_("Writing disklabel to %s.\n"),
1205 partname(disk_device, xbsd_part_index+1, 0));
1206 xbsd_writelabel (xbsd_part, &xbsd_dlabel);
1207#endif
1208 reread_partition_table(0); /* no exit yet */
1209}
1210
1211static int
1212xbsd_create_disklabel (void) {
1213 char c;
1214
1215#if defined (__alpha__)
1216 fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
1217#else
1218 fprintf (stderr, _("%s contains no disklabel.\n"),
1219 partname(disk_device, xbsd_part_index+1, 0));
1220#endif
1221
1222 while (1) {
1223 c = read_char (_("Do you want to create a disklabel? (y/n) "));
1224 if (c == 'y' || c == 'Y') {
1225 if (xbsd_initlabel (
Eric Andersen040f4402003-07-30 08:40:37 +00001226#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
1227 defined (__s390__) || defined (__s390x__)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001228 NULL, &xbsd_dlabel, 0
1229#else
1230 xbsd_part, &xbsd_dlabel, xbsd_part_index
1231#endif
1232 ) == 1) {
1233 xbsd_print_disklabel (1);
1234 return 1;
1235 } else
1236 return 0;
1237 } else if (c == 'n')
1238 return 0;
1239 }
1240}
1241
1242static int
1243edit_int (int def, char *mesg)
1244{
1245 do {
1246 fputs (mesg, stdout);
1247 printf (" (%d): ", def);
1248 if (!read_line ())
1249 return def;
1250 }
1251 while (!isdigit (*line_ptr));
1252 return atoi (line_ptr);
1253}
1254
1255static void
1256xbsd_edit_disklabel (void)
1257{
1258 struct xbsd_disklabel *d;
1259
1260 d = &xbsd_dlabel;
1261
1262#if defined (__alpha__) || defined (__ia64__)
1263 d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,_("bytes/sector"));
1264 d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,_("sectors/track"));
1265 d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,_("tracks/cylinder"));
1266 d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,_("cylinders"));
1267#endif
1268
1269 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
1270 while (1)
1271 {
1272 d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
1273 _("sectors/cylinder"));
1274 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
1275 break;
1276
1277 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1278 }
1279 d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,_("rpm"));
1280 d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
1281 d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
1282 d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,_("cylinderskew"));
1283 d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,_("headswitch"));
1284 d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,_("track-to-track seek"));
1285
1286 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1287}
1288
1289static int
1290xbsd_get_bootstrap (char *path, void *ptr, int size)
1291{
1292 int fdb;
1293
1294 if ((fdb = open (path, O_RDONLY)) < 0)
1295 {
1296 perror (path);
1297 return 0;
1298 }
1299 if (read (fdb, ptr, size) < 0)
1300 {
1301 perror (path);
1302 close (fdb);
1303 return 0;
1304 }
1305 printf (" ... %s\n", path);
1306 close (fdb);
1307 return 1;
1308}
1309
1310static void
1311sync_disks (void)
1312{
1313 printf (_("\nSyncing disks.\n"));
1314 sync ();
1315 sleep (4);
1316}
1317
1318static void
1319xbsd_write_bootstrap (void)
1320{
1321 char *bootdir = BSD_LINUX_BOOTDIR;
1322 char path[MAXPATHLEN];
1323 char *dkbasename;
1324 struct xbsd_disklabel dl;
1325 char *d, *p, *e;
1326 int sector;
1327
1328 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1329 dkbasename = "sd";
1330 else
1331 dkbasename = "wd";
1332
1333 printf (_("Bootstrap: %sboot -> boot%s (%s): "),
1334 dkbasename, dkbasename, dkbasename);
1335 if (read_line ()) {
1336 line_ptr[strlen (line_ptr)-1] = '\0';
1337 dkbasename = line_ptr;
1338 }
1339 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1340 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1341 return;
1342
1343 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1344 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1345 bcopy (d, &dl, sizeof (struct xbsd_disklabel));
1346
1347 /* The disklabel will be overwritten by 0's from bootxx anyway */
1348 bzero (d, sizeof (struct xbsd_disklabel));
1349
1350 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1351 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1352 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1353 return;
1354
1355 e = d + sizeof (struct xbsd_disklabel);
1356 for (p=d; p < e; p++)
1357 if (*p) {
1358 fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
1359 exit ( EXIT_FAILURE );
1360 }
1361
1362 bcopy (&dl, d, sizeof (struct xbsd_disklabel));
1363
1364#if defined (__powerpc__) || defined (__hppa__)
1365 sector = 0;
1366#elif defined (__alpha__)
1367 sector = 0;
1368 alpha_bootblock_checksum (disklabelbuffer);
1369#else
1370 sector = get_start_sect(xbsd_part);
1371#endif
1372
Eric Andersen0a92f352004-03-30 09:21:54 +00001373 if (lseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001374 fdisk_fatal (unable_to_seek);
1375 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1376 fdisk_fatal (unable_to_write);
1377
1378#if defined (__alpha__)
1379 printf (_("Bootstrap installed on %s.\n"), disk_device);
1380#else
1381 printf (_("Bootstrap installed on %s.\n"),
1382 partname (disk_device, xbsd_part_index+1, 0));
1383#endif
1384
1385 sync_disks ();
1386}
1387
1388static void
1389xbsd_change_fstype (void)
1390{
1391 int i;
1392
1393 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1394 xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
1395}
1396
1397static int
1398xbsd_get_part_index (int max)
1399{
1400 char prompt[256];
1401 char l;
1402
1403 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1404 do
1405 l = tolower (read_char (prompt));
1406 while (l < 'a' || l > 'a' + max - 1);
1407 return l - 'a';
1408}
1409
1410static int
1411xbsd_check_new_partition (int *i) {
1412
1413 /* room for more? various BSD flavours have different maxima */
1414 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1415 int t;
1416
1417 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1418 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1419 break;
1420
1421 if (t == BSD_MAXPARTITIONS) {
1422 fprintf (stderr, _("The maximum number of partitions "
1423 "has been created\n"));
1424 return 0;
1425 }
1426 }
1427
1428 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1429
1430 if (*i >= xbsd_dlabel.d_npartitions)
1431 xbsd_dlabel.d_npartitions = (*i) + 1;
1432
1433 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1434 fprintf (stderr, _("This partition already exists.\n"));
1435 return 0;
1436 }
1437
1438 return 1;
1439}
1440
1441static void
1442xbsd_list_types (void) {
1443 list_types (xbsd_fstypes);
1444}
1445
1446static u_short
1447xbsd_dkcksum (struct xbsd_disklabel *lp) {
1448 u_short *start, *end;
1449 u_short sum = 0;
1450
1451 start = (u_short *) lp;
1452 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1453 while (start < end)
1454 sum ^= *start++;
1455 return sum;
1456}
1457
1458static int
1459xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) {
1460 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001461
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001462 get_geometry ();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001463 bzero (d, sizeof (struct xbsd_disklabel));
1464
1465 d -> d_magic = BSD_DISKMAGIC;
1466
1467 if (strncmp (disk_device, "/dev/sd", 7) == 0)
1468 d -> d_type = BSD_DTYPE_SCSI;
1469 else
1470 d -> d_type = BSD_DTYPE_ST506;
1471
1472#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
1473 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
1474#endif
1475
1476#if !defined (__alpha__)
1477 d -> d_flags = BSD_D_DOSPART;
1478#else
1479 d -> d_flags = 0;
1480#endif
1481 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001482 d -> d_nsectors = sectors; /* sectors/track */
1483 d -> d_ntracks = heads; /* tracks/cylinder (heads) */
1484 d -> d_ncylinders = cylinders;
1485 d -> d_secpercyl = sectors * heads;/* sectors/cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001486 if (d -> d_secpercyl == 0)
1487 d -> d_secpercyl = 1; /* avoid segfaults */
1488 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1489
1490 d -> d_rpm = 3600;
1491 d -> d_interleave = 1;
1492 d -> d_trackskew = 0;
1493 d -> d_cylskew = 0;
1494 d -> d_headswitch = 0;
1495 d -> d_trkseek = 0;
1496
1497 d -> d_magic2 = BSD_DISKMAGIC;
1498 d -> d_bbsize = BSD_BBSIZE;
1499 d -> d_sbsize = BSD_SBSIZE;
1500
1501#if !defined (__alpha__)
1502 d -> d_npartitions = 4;
1503 pp = &d -> d_partitions[2]; /* Partition C should be
1504 the NetBSD partition */
1505 pp -> p_offset = get_start_sect(p);
1506 pp -> p_size = get_nr_sects(p);
1507 pp -> p_fstype = BSD_FS_UNUSED;
1508 pp = &d -> d_partitions[3]; /* Partition D should be
1509 the whole disk */
1510 pp -> p_offset = 0;
1511 pp -> p_size = d -> d_secperunit;
1512 pp -> p_fstype = BSD_FS_UNUSED;
1513#elif defined (__alpha__)
1514 d -> d_npartitions = 3;
1515 pp = &d -> d_partitions[2]; /* Partition C should be
1516 the whole disk */
1517 pp -> p_offset = 0;
1518 pp -> p_size = d -> d_secperunit;
1519 pp -> p_fstype = BSD_FS_UNUSED;
1520#endif
1521
1522 return 1;
1523}
1524
1525/*
1526 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1527 * If it has the right magic, return 1.
1528 */
1529static int
1530xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1531{
1532 int t, sector;
1533
1534 /* p is used only to get the starting sector */
1535#if !defined (__alpha__)
1536 sector = (p ? get_start_sect(p) : 0);
1537#elif defined (__alpha__)
1538 sector = 0;
1539#endif
1540
Eric Andersen0a92f352004-03-30 09:21:54 +00001541 if (lseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001542 fdisk_fatal (unable_to_seek);
1543 if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
1544 fdisk_fatal (unable_to_read);
1545
1546 bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1547 d, sizeof (struct xbsd_disklabel));
1548
1549 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
1550 return 0;
1551
1552 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1553 d -> d_partitions[t].p_size = 0;
1554 d -> d_partitions[t].p_offset = 0;
1555 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
1556 }
1557
1558 if (d -> d_npartitions > BSD_MAXPARTITIONS)
1559 fprintf (stderr, _("Warning: too many partitions "
1560 "(%d, maximum is %d).\n"),
1561 d -> d_npartitions, BSD_MAXPARTITIONS);
1562 return 1;
1563}
1564
1565static int
1566xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1567{
Eric Andersen040f4402003-07-30 08:40:37 +00001568 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001569
1570#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1571 sector = get_start_sect(p) + BSD_LABELSECTOR;
1572#else
1573 sector = BSD_LABELSECTOR;
1574#endif
1575
1576 d -> d_checksum = 0;
1577 d -> d_checksum = xbsd_dkcksum (d);
1578
1579 /* This is necessary if we want to write the bootstrap later,
1580 otherwise we'd write the old disklabel with the bootstrap.
1581 */
1582 bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1583 sizeof (struct xbsd_disklabel));
1584
1585#if defined (__alpha__) && BSD_LABELSECTOR == 0
1586 alpha_bootblock_checksum (disklabelbuffer);
Eric Andersen0a92f352004-03-30 09:21:54 +00001587 if (lseek (fd, 0, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001588 fdisk_fatal (unable_to_seek);
1589 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1590 fdisk_fatal (unable_to_write);
1591#else
Eric Andersen0a92f352004-03-30 09:21:54 +00001592 if (lseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001593 SEEK_SET) == -1)
1594 fdisk_fatal (unable_to_seek);
1595 if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel)))
1596 fdisk_fatal (unable_to_write);
1597#endif
1598
1599 sync_disks ();
1600
1601 return 1;
1602}
1603
1604
1605#if !defined (__alpha__)
1606static int
1607xbsd_translate_fstype (int linux_type)
1608{
1609 switch (linux_type)
1610 {
1611 case 0x01: /* DOS 12-bit FAT */
1612 case 0x04: /* DOS 16-bit <32M */
1613 case 0x06: /* DOS 16-bit >=32M */
1614 case 0xe1: /* DOS access */
1615 case 0xe3: /* DOS R/O */
1616 case 0xf2: /* DOS secondary */
1617 return BSD_FS_MSDOS;
1618 case 0x07: /* OS/2 HPFS */
1619 return BSD_FS_HPFS;
1620 default:
1621 return BSD_FS_OTHER;
1622 }
1623}
1624
1625static void
1626xbsd_link_part (void)
1627{
1628 int k, i;
1629 struct partition *p;
1630
1631 k = get_partition (1, partitions);
1632
1633 if (!xbsd_check_new_partition (&i))
1634 return;
1635
1636 p = get_part_table(k);
1637
1638 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1639 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1640 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1641}
1642#endif
1643
1644#if defined (__alpha__)
1645
1646#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001647typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001648#endif
1649
1650static void
1651alpha_bootblock_checksum (char *boot)
1652{
Eric Andersendfcb5b02004-01-30 22:54:20 +00001653 uint64_t *dp, sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001654 int i;
1655
Eric Andersendfcb5b02004-01-30 22:54:20 +00001656 dp = (uint64_t *)boot;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001657 sum = 0;
1658 for (i = 0; i < 63; i++)
1659 sum += dp[i];
1660 dp[63] = sum;
1661}
1662#endif /* __alpha__ */
1663
1664#endif /* OSF_LABEL */
1665
1666#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1667static inline unsigned short
1668__swap16(unsigned short x) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001669 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001670}
1671
Eric Andersenacd244a2002-12-11 03:49:33 +00001672static inline uint32_t
1673__swap32(uint32_t x) {
Eric Andersen040f4402003-07-30 08:40:37 +00001674 return (((x & 0xFF) << 24) |
1675 ((x & 0xFF00) << 8) |
1676 ((x & 0xFF0000) >> 8) |
1677 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001678}
1679#endif
1680
1681#ifdef CONFIG_FEATURE_SGI_LABEL
1682/*
1683 *
1684 * fdisksgilabel.c
1685 *
1686 * Copyright (C) Andreas Neuper, Sep 1998.
1687 * This file may be modified and redistributed under
1688 * the terms of the GNU Public License.
1689 *
1690 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1691 * Internationalization
1692 */
1693
1694
1695static int sgi_other_endian;
1696static int debug;
1697static short sgi_volumes=1;
1698
1699/*
1700 * only dealing with free blocks here
1701 */
1702
Eric Andersen040f4402003-07-30 08:40:37 +00001703typedef struct { unsigned int first; unsigned int last; } freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001704static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1705
1706static void
Eric Andersen040f4402003-07-30 08:40:37 +00001707setfreelist(int i, unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001708 freelist[i].first = f;
1709 freelist[i].last = l;
1710}
1711
1712static void
Eric Andersen040f4402003-07-30 08:40:37 +00001713add2freelist(unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001714 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001715 for ( ; i < 17 ; i++)
1716 if (freelist[i].last == 0)
1717 break;
1718 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001719}
1720
1721static void
1722clearfreelist(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00001723 int i;
1724
1725 for (i = 0; i < 17 ; i++)
1726 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001727}
1728
Eric Andersen040f4402003-07-30 08:40:37 +00001729static unsigned int
1730isinfreelist(unsigned int b) {
1731 int i;
1732
1733 for (i = 0; i < 17 ; i++)
1734 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001735 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001736 return 0;
1737}
1738 /* return last vacant block of this stride (never 0). */
1739 /* the '>=' is not quite correct, but simplifies the code */
1740/*
1741 * end of free blocks section
1742 */
1743
1744static const struct systypes sgi_sys_types[] = {
1745/* SGI_VOLHDR */ {"\x00" "SGI volhdr" },
1746/* 0x01 */ {"\x01" "SGI trkrepl" },
1747/* 0x02 */ {"\x02" "SGI secrepl" },
1748/* SGI_SWAP */ {"\x03" "SGI raw" },
1749/* 0x04 */ {"\x04" "SGI bsd" },
1750/* 0x05 */ {"\x05" "SGI sysv" },
1751/* ENTIRE_DISK */ {"\x06" "SGI volume" },
1752/* SGI_EFS */ {"\x07" "SGI efs" },
1753/* 0x08 */ {"\x08" "SGI lvol" },
1754/* 0x09 */ {"\x09" "SGI rlvol" },
1755/* SGI_XFS */ {"\x0a" "SGI xfs" },
1756/* SGI_XFSLOG */ {"\x0b" "SGI xfslog" },
1757/* SGI_XLV */ {"\x0c" "SGI xlv" },
1758/* SGI_XVM */ {"\x0d" "SGI xvm" },
1759/* LINUX_SWAP */ {"\x82" "Linux swap" },
1760/* LINUX_NATIVE */ {"\x83" "Linux native" },
1761/* LINUX_LVM */ {"\x8d" "Linux LVM" },
1762/* LINUX_RAID */ {"\xfd" "Linux RAID" },
1763 { NULL }
1764};
1765
1766
1767static int
1768sgi_get_nsect(void) {
1769 return SGI_SSWAP16(sgilabel->devparam.nsect);
1770}
1771
1772static int
1773sgi_get_ntrks(void) {
1774 return SGI_SSWAP16(sgilabel->devparam.ntrks);
1775}
1776
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001777static void
1778sgi_nolabel(void) {
1779 sgilabel->magic = 0;
1780 sgi_label = 0;
1781 partitions = 4;
1782}
1783
1784static unsigned int
Eric Andersen040f4402003-07-30 08:40:37 +00001785two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001786 int i=0;
1787 unsigned int sum=0;
1788
Eric Andersen040f4402003-07-30 08:40:37 +00001789 size /= sizeof(unsigned int);
1790 for (i = 0; i < size; i++)
1791 sum -= SGI_SSWAP32(base[i]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001792 return sum;
1793}
1794
1795static int
1796check_sgi_label(void) {
1797 if (sizeof(sgilabel) > 512) {
1798 fprintf(stderr,
1799 _("According to MIPS Computer Systems, Inc the "
1800 "Label must not contain more than 512 bytes\n"));
1801 exit(1);
1802 }
1803
1804 if (sgilabel->magic != SGI_LABEL_MAGIC &&
1805 sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1806 sgi_label = 0;
1807 sgi_other_endian = 0;
1808 return 0;
1809 }
1810
1811 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1812 /*
1813 * test for correct checksum
1814 */
Eric Andersen040f4402003-07-30 08:40:37 +00001815 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1816 sizeof(*sgilabel))) {
1817 fprintf(stderr,
1818 _("Detected sgi disklabel with wrong checksum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001819 }
1820 update_units();
1821 sgi_label = 1;
1822 partitions= 16;
1823 sgi_volumes = 15;
1824 return 1;
1825}
1826
Eric Andersen040f4402003-07-30 08:40:37 +00001827static unsigned int
1828sgi_get_start_sector(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001829 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1830}
1831
Eric Andersen040f4402003-07-30 08:40:37 +00001832static unsigned int
1833sgi_get_num_sectors(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001834 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1835}
1836
1837static int
Eric Andersen040f4402003-07-30 08:40:37 +00001838sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001839{
1840 return SGI_SSWAP32(sgilabel->partitions[i].id);
1841}
1842
1843static int
1844sgi_get_bootpartition(void)
1845{
1846 return SGI_SSWAP16(sgilabel->boot_part);
1847}
1848
1849static int
1850sgi_get_swappartition(void)
1851{
1852 return SGI_SSWAP16(sgilabel->swap_part);
1853}
1854
1855static void
Eric Andersen040f4402003-07-30 08:40:37 +00001856sgi_list_table(int xtra) {
Eric Andersen99a75d12003-08-08 20:04:56 +00001857 int i, w, wd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001858 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001859
Eric Andersen040f4402003-07-30 08:40:37 +00001860 if(xtra) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001861 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1862 "%d cylinders, %d physical cylinders\n"
1863 "%d extra sects/cyl, interleave %d:1\n"
1864 "%s\n"
1865 "Units = %s of %d * 512 bytes\n\n"),
1866 disk_device, heads, sectors, cylinders,
1867 SGI_SSWAP16(sgiparam.pcylcount),
1868 SGI_SSWAP16(sgiparam.sparecyl),
1869 SGI_SSWAP16(sgiparam.ilfact),
1870 (char *)sgilabel,
1871 str_units(PLURAL), units_per_sector);
1872 } else {
1873 printf( _("\nDisk %s (SGI disk label): "
1874 "%d heads, %d sectors, %d cylinders\n"
1875 "Units = %s of %d * 512 bytes\n\n"),
1876 disk_device, heads, sectors, cylinders,
1877 str_units(PLURAL), units_per_sector );
1878 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001879
1880 w = strlen(disk_device);
1881 wd = strlen(_("Device"));
1882 if (w < wd)
1883 w = wd;
1884
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001885 printf(_("----- partitions -----\n"
1886 "Pt# %*s Info Start End Sectors Id System\n"),
Eric Andersen99a75d12003-08-08 20:04:56 +00001887 w + 2, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001888 for (i = 0 ; i < partitions; i++) {
1889 if( sgi_get_num_sectors(i) || debug ) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001890 uint32_t start = sgi_get_start_sector(i);
1891 uint32_t len = sgi_get_num_sectors(i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001892 kpi++; /* only count nonempty partitions */
1893 printf(
1894 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1895/* fdisk part number */ i+1,
Eric Andersen99a75d12003-08-08 20:04:56 +00001896/* device */ partname(disk_device, kpi, w+3),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001897/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1898/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1899/* start */ (long) scround(start),
1900/* end */ (long) scround(start+len)-1,
1901/* no odd flag on end */ (long) len,
1902/* type id */ sgi_get_sysid(i),
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001903/* type name */ partition_type(sgi_get_sysid(i)));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001904 }
1905 }
1906 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1907 "----- Directory Entries -----\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00001908 sgilabel->boot_file);
1909 for (i = 0 ; i < sgi_volumes; i++) {
1910 if (sgilabel->directory[i].vol_file_size) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001911 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1912 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001913 char*name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001914
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001915 printf(_("%2d: %-10s sector%5u size%8u\n"),
1916 i, name, (unsigned int) start, (unsigned int) len);
1917 }
1918 }
1919}
1920
1921static void
1922sgi_set_bootpartition( int i )
1923{
1924 sgilabel->boot_part = SGI_SSWAP16(((short)i));
1925}
1926
Eric Andersen040f4402003-07-30 08:40:37 +00001927static unsigned int
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001928sgi_get_lastblock(void) {
1929 return heads * sectors * cylinders;
1930}
1931
1932static void
1933sgi_set_swappartition( int i ) {
1934 sgilabel->swap_part = SGI_SSWAP16(((short)i));
1935}
1936
1937static int
Eric Andersen040f4402003-07-30 08:40:37 +00001938sgi_check_bootfile(const char* aFile) {
1939
1940 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1941 printf(_("\nInvalid Bootfile!\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001942 "\tThe bootfile must be an absolute non-zero pathname,\n"
Eric Andersen040f4402003-07-30 08:40:37 +00001943 "\te.g. \"/unix\" or \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001944 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001945 } else {
1946 if (strlen(aFile) > 16) {
1947 printf(_("\n\tName of Bootfile too long: "
1948 "16 bytes maximum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001949 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001950 } else {
1951 if (aFile[0] != '/') {
1952 printf(_("\n\tBootfile must have a "
1953 "fully qualified pathname.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001954 return 0;
1955 }
Eric Andersen040f4402003-07-30 08:40:37 +00001956 }
1957 }
1958 if (strncmp(aFile, sgilabel->boot_file, 16)) {
1959 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1960 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001961 /* filename is correct and did change */
1962 return 1;
1963 }
1964 return 0; /* filename did not change */
1965}
1966
1967static const char *
1968sgi_get_bootfile(void) {
1969 return sgilabel->boot_file;
1970}
1971
1972static void
Eric Andersen040f4402003-07-30 08:40:37 +00001973sgi_set_bootfile(const char* aFile) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001974 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001975
1976 if (sgi_check_bootfile(aFile)) {
1977 while (i < 16) {
1978 if ((aFile[i] != '\n') /* in principle caught again by next line */
1979 && (strlen(aFile) > i))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001980 sgilabel->boot_file[i] = aFile[i];
1981 else
1982 sgilabel->boot_file[i] = 0;
1983 i++;
1984 }
Eric Andersen040f4402003-07-30 08:40:37 +00001985 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001986 }
1987}
1988
1989static void
1990create_sgiinfo(void)
1991{
1992 /* I keep SGI's habit to write the sgilabel to the second block */
Eric Andersen040f4402003-07-30 08:40:37 +00001993 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
1994 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
1995 strncpy(sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001996}
1997
Eric Andersen040f4402003-07-30 08:40:37 +00001998static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001999
2000static void
Eric Andersen040f4402003-07-30 08:40:37 +00002001sgi_write_table(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002002 sgilabel->csum = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002003 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002004 (unsigned int*)sgilabel,
Eric Andersen040f4402003-07-30 08:40:37 +00002005 sizeof(*sgilabel)));
2006 assert(two_s_complement_32bit_sum(
2007 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
2008 if (lseek(fd, 0, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002009 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002010 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002011 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002012 if (! strncmp(sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002013 /*
Eric Andersen040f4402003-07-30 08:40:37 +00002014 * keep this habit of first writing the "sgilabel".
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002015 * I never tested whether it works without (AN 981002).
2016 */
Eric Andersen040f4402003-07-30 08:40:37 +00002017 sgiinfo *info = fill_sgiinfo();
2018 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
Eric Andersenbbbbcfe2004-03-30 09:33:18 +00002019 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002020 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002021 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002022 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002023 free(info);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002024 }
2025}
2026
2027static int
Eric Andersen040f4402003-07-30 08:40:37 +00002028compare_start(int *x, int *y) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002029 /*
2030 * sort according to start sectors
2031 * and prefers largest partition:
2032 * entry zero is entire disk entry
2033 */
Eric Andersen040f4402003-07-30 08:40:37 +00002034 unsigned int i = *x;
2035 unsigned int j = *y;
2036 unsigned int a = sgi_get_start_sector(i);
2037 unsigned int b = sgi_get_start_sector(j);
2038 unsigned int c = sgi_get_num_sectors(i);
2039 unsigned int d = sgi_get_num_sectors(j);
2040
2041 if (a == b)
2042 return (d > c) ? 1 : (d == c) ? 0 : -1;
2043 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002044}
2045
2046
2047static int
Eric Andersen040f4402003-07-30 08:40:37 +00002048verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002049{
2050 int Index[16]; /* list of valid partitions */
2051 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
Eric Andersen040f4402003-07-30 08:40:37 +00002052 int entire = 0, i = 0;
2053 unsigned int start = 0;
2054 long long gap = 0; /* count unused blocks */
2055 unsigned int lastblock = sgi_get_lastblock();
2056
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002057 clearfreelist();
Eric Andersen040f4402003-07-30 08:40:37 +00002058 for (i=0; i<16; i++) {
2059 if (sgi_get_num_sectors(i) != 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002060 Index[sortcount++]=i;
Eric Andersen040f4402003-07-30 08:40:37 +00002061 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2062 if (entire++ == 1) {
2063 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002064 printf(_("More than one entire disk entry present.\n"));
2065 }
2066 }
2067 }
2068 }
Eric Andersen040f4402003-07-30 08:40:37 +00002069 if (sortcount == 0) {
2070 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002071 printf(_("No partitions defined\n"));
Eric Andersen040f4402003-07-30 08:40:37 +00002072 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002073 }
Eric Andersen040f4402003-07-30 08:40:37 +00002074 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2075 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2076 if ((Index[0] != 10) && verbose)
2077 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2078 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2079 printf(_("The entire disk partition should start "
2080 "at block 0,\n"
2081 "not at diskblock %d.\n"),
2082 sgi_get_start_sector(Index[0]));
2083 if (debug) /* I do not understand how some disks fulfil it */
2084 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2085 printf(_("The entire disk partition is only %d diskblock large,\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002086 "but the disk is %d diskblocks long.\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00002087 sgi_get_num_sectors(Index[0]), lastblock);
2088 lastblock = sgi_get_num_sectors(Index[0]);
2089 } else {
2090 if (verbose)
2091 printf(_("One Partition (#11) should cover the entire disk.\n"));
2092 if (debug>2)
2093 printf("sysid=%d\tpartition=%d\n",
2094 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002095 }
Eric Andersen040f4402003-07-30 08:40:37 +00002096 for (i=1, start=0; i<sortcount; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002097 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
Eric Andersen040f4402003-07-30 08:40:37 +00002098
2099 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2100 if (debug) /* I do not understand how some disks fulfil it */
2101 if (verbose)
2102 printf(_("Partition %d does not start on cylinder boundary.\n"),
2103 Index[i]+1);
2104 }
2105 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2106 if (debug) /* I do not understand how some disks fulfil it */
2107 if (verbose)
2108 printf(_("Partition %d does not end on cylinder boundary.\n"),
2109 Index[i]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002110 }
2111 /* We cannot handle several "entire disk" entries. */
Eric Andersen040f4402003-07-30 08:40:37 +00002112 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2113 if (start > sgi_get_start_sector(Index[i])) {
2114 if (verbose)
2115 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002116 Index[i-1]+1, Index[i]+1,
Eric Andersen040f4402003-07-30 08:40:37 +00002117 start - sgi_get_start_sector(Index[i]));
2118 if (gap > 0) gap = -gap;
2119 if (gap == 0) gap = -1;
2120 }
2121 if (start < sgi_get_start_sector(Index[i])) {
2122 if (verbose)
2123 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2124 sgi_get_start_sector(Index[i]) - start,
2125 start, sgi_get_start_sector(Index[i])-1);
2126 gap += sgi_get_start_sector(Index[i]) - start;
2127 add2freelist(start, sgi_get_start_sector(Index[i]));
2128 }
2129 start = sgi_get_start_sector(Index[i])
2130 + sgi_get_num_sectors(Index[i]);
2131 if (debug > 1) {
2132 if (verbose)
2133 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002134 sgi_get_start_sector(Index[i]),
2135 sgi_get_num_sectors(Index[i]),
Eric Andersen040f4402003-07-30 08:40:37 +00002136 sgi_get_sysid(Index[i]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002137 }
2138 }
Eric Andersen040f4402003-07-30 08:40:37 +00002139 if (start < lastblock) {
2140 if (verbose)
2141 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2142 lastblock - start, start, lastblock-1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002143 gap += lastblock - start;
Eric Andersen040f4402003-07-30 08:40:37 +00002144 add2freelist(start, lastblock);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002145 }
2146 /*
2147 * Done with arithmetics
2148 * Go for details now
2149 */
Eric Andersen040f4402003-07-30 08:40:37 +00002150 if (verbose) {
2151 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2152 printf(_("\nThe boot partition does not exist.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002153 }
Eric Andersen040f4402003-07-30 08:40:37 +00002154 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2155 printf(_("\nThe swap partition does not exist.\n"));
2156 } else {
2157 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2158 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2159 printf(_("\nThe swap partition has no swap type.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002160 }
Eric Andersen040f4402003-07-30 08:40:37 +00002161 if (sgi_check_bootfile("/unix"))
2162 printf(_("\tYou have chosen an unusual boot file name.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002163 }
Eric Andersen040f4402003-07-30 08:40:37 +00002164 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002165}
2166
2167static int
2168sgi_gaps(void) {
2169 /*
2170 * returned value is:
2171 * = 0 : disk is properly filled to the rim
2172 * < 0 : there is an overlap
2173 * > 0 : there is still some vacant space
2174 */
2175 return verify_sgi(0);
2176}
2177
2178static void
2179sgi_change_sysid( int i, int sys )
2180{
2181 if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
2182 {
2183 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2184 return;
2185 }
2186 if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2187 && (sgi_get_start_sector(i)<1) )
2188 {
2189 read_chars(
2190 _("It is highly recommended that the partition at offset 0\n"
2191 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2192 "retrieve from its directory standalone tools like sash and fx.\n"
2193 "Only the \"SGI volume\" entire disk section may violate this.\n"
2194 "Type YES if you are sure about tagging this partition differently.\n"));
2195 if (strcmp (line_ptr, _("YES\n")))
2196 return;
2197 }
2198 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2199}
2200
2201/* returns partition index of first entry marked as entire disk */
2202static int
2203sgi_entire(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00002204 int i;
2205
2206 for(i=0; i<16; i++)
2207 if(sgi_get_sysid(i) == SGI_VOLUME)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002208 return i;
2209 return -1;
2210}
2211
2212static void
Eric Andersen040f4402003-07-30 08:40:37 +00002213sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
2214
2215 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2216 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2217 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002218 set_changed(i);
Eric Andersen040f4402003-07-30 08:40:37 +00002219 if (sgi_gaps() < 0) /* rebuild freelist */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002220 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2221}
2222
2223static void
2224sgi_set_entire(void) {
2225 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002226
2227 for(n=10; n < partitions; n++) {
2228 if(!sgi_get_num_sectors(n) ) {
2229 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002230 break;
2231 }
2232 }
2233}
2234
2235static void
2236sgi_set_volhdr(void)
2237{
2238 int n;
2239 for( n=8; n<partitions; n++ )
2240 {
2241 if(!sgi_get_num_sectors( n ) )
2242 {
2243 /*
2244 * 5 cylinders is an arbitrary value I like
2245 * IRIX 5.3 stored files in the volume header
2246 * (like sash, symmon, fx, ide) with ca. 3200
2247 * sectors.
2248 */
2249 if( heads * sectors * 5 < sgi_get_lastblock() )
2250 sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
2251 break;
2252 }
2253 }
2254}
2255
2256static void
2257sgi_delete_partition( int i )
2258{
2259 sgi_set_partition( i, 0, 0, 0 );
2260}
2261
2262static void
2263sgi_add_partition( int n, int sys )
2264{
2265 char mesg[256];
Eric Andersen040f4402003-07-30 08:40:37 +00002266 unsigned int first=0, last=0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002267
2268 if( n == 10 ) {
2269 sys = SGI_VOLUME;
2270 } else if ( n == 8 ) {
2271 sys = 0;
2272 }
Eric Andersen040f4402003-07-30 08:40:37 +00002273 if(sgi_get_num_sectors(n)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002274 printf(_("Partition %d is already defined. Delete "
2275 "it before re-adding it.\n"), n + 1);
2276 return;
2277 }
Eric Andersen040f4402003-07-30 08:40:37 +00002278 if( (sgi_entire() == -1) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002279 printf(_("Attempting to generate entire disk entry automatically.\n"));
2280 sgi_set_entire();
2281 sgi_set_volhdr();
2282 }
Eric Andersen040f4402003-07-30 08:40:37 +00002283 if( (sgi_gaps() == 0) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002284 printf(_("The entire disk is already covered with partitions.\n"));
2285 return;
2286 }
Eric Andersen040f4402003-07-30 08:40:37 +00002287 if(sgi_gaps() < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002288 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2289 return;
2290 }
2291 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2292 for(;;) {
2293 if(sys == SGI_VOLUME) {
2294 last = sgi_get_lastblock();
2295 first = read_int(0, 0, last-1, 0, mesg);
2296 if( first != 0 ) {
2297 printf(_("It is highly recommended that eleventh partition\n"
2298 "covers the entire disk and is of type `SGI volume'\n"));
2299 }
2300 } else {
2301 first = freelist[0].first;
2302 last = freelist[0].last;
2303 first = read_int(scround(first), scround(first), scround(last)-1,
2304 0, mesg);
2305 }
2306 if (display_in_cyl_units)
2307 first *= units_per_sector;
2308 else
2309 first = first; /* align to cylinder if you know how ... */
2310 if( !last )
2311 last = isinfreelist(first);
2312 if( last == 0 ) {
2313 printf(_("You will get a partition overlap on the disk. "
2314 "Fix it first!\n"));
2315 } else
2316 break;
2317 }
2318 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2319 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2320 scround(first), mesg)+1;
2321 if (display_in_cyl_units)
2322 last *= units_per_sector;
2323 else
2324 last = last; /* align to cylinder if You know how ... */
2325 if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
2326 printf(_("It is highly recommended that eleventh partition\n"
2327 "covers the entire disk and is of type `SGI volume'\n"));
2328 sgi_set_partition( n, first, last-first, sys );
2329}
2330
Eric Andersen040f4402003-07-30 08:40:37 +00002331#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002332static void
2333create_sgilabel(void)
2334{
2335 struct hd_geometry geometry;
Eric Andersen040f4402003-07-30 08:40:37 +00002336 struct {
2337 unsigned int start;
2338 unsigned int nsect;
2339 int sysid;
2340 } old[4];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002341 int i=0;
Eric Andersen040f4402003-07-30 08:40:37 +00002342 long longsectors; /* the number of sectors on the device */
2343 int res; /* the result from the ioctl */
2344 int sec_fac; /* the sector factor */
2345
2346 sec_fac = sector_size / 512; /* determine the sector factor */
2347
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002348 fprintf( stderr,
2349 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2350 "until you decide to write them. After that, of course, the previous\n"
2351 "content will be unrecoverably lost.\n\n"));
2352
2353 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
Eric Andersen040f4402003-07-30 08:40:37 +00002354 res = ioctl(fd, BLKGETSIZE, &longsectors);
2355 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002356 heads = geometry.heads;
2357 sectors = geometry.sectors;
Eric Andersen040f4402003-07-30 08:40:37 +00002358 if (res == 0) {
2359 /* the get device size ioctl was successful */
2360 cylinders = longsectors / (heads * sectors);
2361 cylinders /= sec_fac;
2362 } else {
2363 /* otherwise print error and use truncated version */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002364 cylinders = geometry.cylinders;
Eric Andersen040f4402003-07-30 08:40:37 +00002365 fprintf(stderr,
2366 _("Warning: BLKGETSIZE ioctl failed on %s. "
2367 "Using geometry cylinder value of %d.\n"
2368 "This value may be truncated for devices"
2369 " > 33.8 GB.\n"), disk_device, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002370 }
Eric Andersen040f4402003-07-30 08:40:37 +00002371 }
2372 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002373 old[i].sysid = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002374 if(valid_part_table_flag(MBRbuffer)) {
2375 if(get_part_table(i)->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002376 old[i].sysid = get_part_table(i)->sys_ind;
Eric Andersen040f4402003-07-30 08:40:37 +00002377 old[i].start = get_start_sect(get_part_table(i));
2378 old[i].nsect = get_nr_sects(get_part_table(i));
2379 printf(_("Trying to keep parameters of partition %d.\n"), i);
2380 if (debug)
2381 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2382 old[i].sysid, old[i].start, old[i].nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002383 }
2384 }
2385 }
Eric Andersen040f4402003-07-30 08:40:37 +00002386
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002387 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2388 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2389 sgilabel->boot_part = SGI_SSWAP16(0);
2390 sgilabel->swap_part = SGI_SSWAP16(1);
2391
2392 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2393 memset(sgilabel->boot_file, 0, 16);
2394 strcpy(sgilabel->boot_file, "/unix");
2395
2396 sgilabel->devparam.skew = (0);
2397 sgilabel->devparam.gap1 = (0);
2398 sgilabel->devparam.gap2 = (0);
2399 sgilabel->devparam.sparecyl = (0);
2400 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2401 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2402 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
2403 /* tracks/cylinder (heads) */
2404 sgilabel->devparam.cmd_tag_queue_depth = (0);
2405 sgilabel->devparam.unused0 = (0);
2406 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2407 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
2408 /* sectors/track */
2409 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2410 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2411 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
2412 IGNORE_ERRORS|RESEEK);
2413 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2414 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2415 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2416 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2417 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2418 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2419 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2420 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2421 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2422 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2423 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2424 sgi_label = 1;
2425 partitions = 16;
2426 sgi_volumes = 15;
2427 sgi_set_entire();
2428 sgi_set_volhdr();
Eric Andersen040f4402003-07-30 08:40:37 +00002429 for (i = 0; i < 4; i++) {
2430 if(old[i].sysid) {
2431 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002432 }
2433 }
2434}
2435
2436static void
2437sgi_set_xcyl(void)
2438{
2439 /* do nothing in the beginning */
2440}
Eric Andersen040f4402003-07-30 08:40:37 +00002441#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002442
2443/* _____________________________________________________________
2444 */
2445
Eric Andersen040f4402003-07-30 08:40:37 +00002446static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002447fill_sgiinfo(void)
2448{
Eric Andersen040f4402003-07-30 08:40:37 +00002449 sgiinfo *info = calloc(1, sizeof(sgiinfo));
2450
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002451 info->magic=SGI_SSWAP32(SGI_INFO_MAGIC);
2452 info->b1=SGI_SSWAP32(-1);
2453 info->b2=SGI_SSWAP16(-1);
2454 info->b3=SGI_SSWAP16(1);
2455 /* You may want to replace this string !!!!!!! */
2456 strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" );
2457 strcpy( info->serial, "0000" );
2458 info->check1816 = SGI_SSWAP16(18*256 +16 );
2459 strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
2460 return info;
2461}
2462#endif /* SGI_LABEL */
2463
2464
2465#ifdef CONFIG_FEATURE_SUN_LABEL
2466/*
2467 * fdisksunlabel.c
2468 *
2469 * I think this is mostly, or entirely, due to
2470 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2471 *
2472 * Merged with fdisk for other architectures, aeb, June 1998.
2473 *
2474 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2475 * Internationalization
2476 */
2477
2478
2479static int sun_other_endian;
2480static int scsi_disk;
2481static int floppy;
2482
2483#ifndef IDE0_MAJOR
2484#define IDE0_MAJOR 3
2485#endif
2486#ifndef IDE1_MAJOR
2487#define IDE1_MAJOR 22
2488#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002489
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002490static void guess_device_type(void) {
2491 struct stat bootstat;
2492
2493 if (fstat (fd, &bootstat) < 0) {
2494 scsi_disk = 0;
2495 floppy = 0;
2496 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002497 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2498 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002499 scsi_disk = 0;
2500 floppy = 0;
2501 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002502 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002503 scsi_disk = 0;
2504 floppy = 1;
2505 } else {
2506 scsi_disk = 1;
2507 floppy = 0;
2508 }
2509}
2510
2511static const struct systypes sun_sys_types[] = {
2512/* 0 */ {"\x00" "Empty" },
2513/* 1 */ {"\x01" "Boot" },
2514/* 2 */ {"\x02" "SunOS root" },
2515/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
2516/* 4 */ {"\x04" "SunOS usr" },
2517/* WHOLE_DISK */ {"\x05" "Whole disk" },
2518/* 6 */ {"\x06" "SunOS stand" },
2519/* 7 */ {"\x07" "SunOS var" },
2520/* 8 */ {"\x08" "SunOS home" },
2521/* LINUX_SWAP */ {"\x82" "Linux swap" },
2522/* LINUX_NATIVE */ {"\x83" "Linux native" },
2523/* 0x8e */ {"\x8e" "Linux LVM" },
2524/* New (2.2.x) raid partition with autodetect using persistent superblock */
2525/* 0xfd */ {"\xfd" "Linux raid autodetect" },
2526 { NULL }
2527};
2528
2529
2530static void
2531set_sun_partition(int i, uint start, uint stop, int sysid) {
2532 sunlabel->infos[i].id = sysid;
2533 sunlabel->partitions[i].start_cylinder =
2534 SUN_SSWAP32(start / (heads * sectors));
2535 sunlabel->partitions[i].num_sectors =
2536 SUN_SSWAP32(stop - start);
2537 set_changed(i);
2538}
2539
2540static void
2541sun_nolabel(void) {
2542 sun_label = 0;
2543 sunlabel->magic = 0;
2544 partitions = 4;
2545}
2546
2547static int
2548check_sun_label(void) {
2549 unsigned short *ush;
2550 int csum;
2551
2552 if (sunlabel->magic != SUN_LABEL_MAGIC &&
2553 sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2554 sun_label = 0;
2555 sun_other_endian = 0;
2556 return 0;
2557 }
2558 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2559 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2560 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2561 if (csum) {
2562 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2563 "Probably you'll have to set all the values,\n"
2564 "e.g. heads, sectors, cylinders and partitions\n"
2565 "or force a fresh label (s command in main menu)\n"));
2566 } else {
2567 heads = SUN_SSWAP16(sunlabel->ntrks);
2568 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2569 sectors = SUN_SSWAP16(sunlabel->nsect);
2570 }
2571 update_units();
2572 sun_label = 1;
2573 partitions = 8;
2574 return 1;
2575}
2576
2577static const struct sun_predefined_drives {
2578 const char *vendor;
2579 const char *model;
2580 unsigned short sparecyl;
2581 unsigned short ncyl;
2582 unsigned short nacyl;
2583 unsigned short pcylcount;
2584 unsigned short ntrks;
2585 unsigned short nsect;
2586 unsigned short rspeed;
2587} sun_drives[] = {
2588{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2589{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2590{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2591{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2592{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2593{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2594{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2595{"","SUN0104",1,974,2,1019,6,35,3662},
2596{"","SUN0207",4,1254,2,1272,9,36,3600},
2597{"","SUN0327",3,1545,2,1549,9,46,3600},
2598{"","SUN0340",0,1538,2,1544,6,72,4200},
2599{"","SUN0424",2,1151,2,2500,9,80,4400},
2600{"","SUN0535",0,1866,2,2500,7,80,5400},
2601{"","SUN0669",5,1614,2,1632,15,54,3600},
2602{"","SUN1.0G",5,1703,2,1931,15,80,3597},
2603{"","SUN1.05",0,2036,2,2038,14,72,5400},
2604{"","SUN1.3G",6,1965,2,3500,17,80,5400},
2605{"","SUN2.1G",0,2733,2,3500,19,80,5400},
2606{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2607};
2608
2609static const struct sun_predefined_drives *
2610sun_autoconfigure_scsi(void) {
2611 const struct sun_predefined_drives *p = NULL;
2612
2613#ifdef SCSI_IOCTL_GET_IDLUN
2614 unsigned int id[2];
2615 char buffer[2048];
2616 char buffer2[2048];
2617 FILE *pfd;
2618 char *vendor;
2619 char *model;
2620 char *q;
2621 int i;
2622
2623 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2624 sprintf(buffer,
2625 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2626#if 0
2627 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2628#else
2629 /* This is very wrong (works only if you have one HBA),
2630 but I haven't found a way how to get hostno
2631 from the current kernel */
2632 0,
2633#endif
2634 (id[0]>>16)&0xff,
2635 id[0]&0xff,
2636 (id[0]>>8)&0xff);
2637 pfd = fopen("/proc/scsi/scsi","r");
2638 if (pfd) {
2639 while (fgets(buffer2,2048,pfd)) {
2640 if (!strcmp(buffer, buffer2)) {
2641 if (fgets(buffer2,2048,pfd)) {
2642 q = strstr(buffer2,"Vendor: ");
2643 if (q) {
2644 q += 8;
2645 vendor = q;
2646 q = strstr(q," ");
2647 *q++ = 0; /* truncate vendor name */
2648 q = strstr(q,"Model: ");
2649 if (q) {
2650 *q = 0;
2651 q += 7;
2652 model = q;
2653 q = strstr(q," Rev: ");
2654 if (q) {
2655 *q = 0;
2656 for (i = 0; i < SIZE(sun_drives); i++) {
2657 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2658 continue;
2659 if (!strstr(model, sun_drives[i].model))
2660 continue;
2661 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2662 p = sun_drives + i;
2663 break;
2664 }
2665 }
2666 }
2667 }
2668 }
2669 break;
2670 }
2671 }
2672 fclose(pfd);
2673 }
2674 }
2675#endif
2676 return p;
2677}
2678
2679static void create_sunlabel(void)
2680{
2681 struct hd_geometry geometry;
2682 unsigned int ndiv;
2683 int i;
2684 unsigned char c;
2685 const struct sun_predefined_drives *p = NULL;
2686
2687 fprintf(stderr,
2688 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2689 "until you decide to write them. After that, of course, the previous\n"
2690 "content won't be recoverable.\n\n"));
2691#if BYTE_ORDER == LITTLE_ENDIAN
2692 sun_other_endian = 1;
2693#else
2694 sun_other_endian = 0;
2695#endif
2696 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2697 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2698 if (!floppy) {
2699 puts(_("Drive type\n"
2700 " ? auto configure\n"
2701 " 0 custom (with hardware detected defaults)"));
2702 for (i = 0; i < SIZE(sun_drives); i++) {
2703 printf(" %c %s%s%s\n",
2704 i + 'a', sun_drives[i].vendor,
2705 (*sun_drives[i].vendor) ? " " : "",
2706 sun_drives[i].model);
2707 }
2708 for (;;) {
2709 c = read_char(_("Select type (? for auto, 0 for custom): "));
2710 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2711 p = sun_drives + c - 'a';
2712 break;
2713 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2714 p = sun_drives + c - 'A';
2715 break;
2716 } else if (c == '0') {
2717 break;
2718 } else if (c == '?' && scsi_disk) {
2719 p = sun_autoconfigure_scsi();
2720 if (!p)
2721 printf(_("Autoconfigure failed.\n"));
2722 else
2723 break;
2724 }
2725 }
2726 }
2727 if (!p || floppy) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002728 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002729 heads = geometry.heads;
2730 sectors = geometry.sectors;
2731 cylinders = geometry.cylinders;
2732 } else {
2733 heads = 0;
2734 sectors = 0;
2735 cylinders = 0;
2736 }
2737 if (floppy) {
2738 sunlabel->nacyl = 0;
2739 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2740 sunlabel->rspeed = SUN_SSWAP16(300);
2741 sunlabel->ilfact = SUN_SSWAP16(1);
2742 sunlabel->sparecyl = 0;
2743 } else {
2744 heads = read_int(1,heads,1024,0,_("Heads"));
2745 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2746 if (cylinders)
2747 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2748 else
2749 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2750 sunlabel->nacyl =
2751 SUN_SSWAP16(read_int(0,2,65535,0,
2752 _("Alternate cylinders")));
2753 sunlabel->pcylcount =
2754 SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl),
2755 65535,0,_("Physical cylinders")));
2756 sunlabel->rspeed =
2757 SUN_SSWAP16(read_int(1,5400,100000,0,
2758 _("Rotation speed (rpm)")));
2759 sunlabel->ilfact =
2760 SUN_SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
2761 sunlabel->sparecyl =
2762 SUN_SSWAP16(read_int(0,0,sectors,0,
2763 _("Extra sectors per cylinder")));
2764 }
2765 } else {
2766 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2767 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2768 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2769 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2770 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2771 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2772 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2773 sunlabel->ilfact = SUN_SSWAP16(1);
2774 cylinders = p->ncyl;
2775 heads = p->ntrks;
2776 sectors = p->nsect;
2777 puts(_("You may change all the disk params from the x menu"));
2778 }
2779
2780 snprintf(sunlabel->info, sizeof(sunlabel->info),
2781 "%s%s%s cyl %d alt %d hd %d sec %d",
2782 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2783 p ? p->model
2784 : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2785 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2786
2787 sunlabel->ntrks = SUN_SSWAP16(heads);
2788 sunlabel->nsect = SUN_SSWAP16(sectors);
2789 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2790 if (floppy)
2791 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2792 else {
2793 if (cylinders * heads * sectors >= 150 * 2048) {
2794 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2795 } else
2796 ndiv = cylinders * 2 / 3;
2797 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2798 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2799 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2800 }
2801 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2802 {
2803 unsigned short *ush = (unsigned short *)sunlabel;
2804 unsigned short csum = 0;
2805 while(ush < (unsigned short *)(&sunlabel->csum))
2806 csum ^= *ush++;
2807 sunlabel->csum = csum;
2808 }
2809
2810 set_all_unchanged();
2811 set_changed(0);
2812 get_boot(create_empty_sun);
2813}
2814
2815static void
2816toggle_sunflags(int i, unsigned char mask) {
2817 if (sunlabel->infos[i].flags & mask)
2818 sunlabel->infos[i].flags &= ~mask;
2819 else sunlabel->infos[i].flags |= mask;
2820 set_changed(i);
2821}
2822
2823static void
2824fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) {
2825 int i, continuous = 1;
2826 *start = 0; *stop = cylinders * heads * sectors;
2827 for (i = 0; i < partitions; i++) {
2828 if (sunlabel->partitions[i].num_sectors
2829 && sunlabel->infos[i].id
2830 && sunlabel->infos[i].id != WHOLE_DISK) {
2831 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2832 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2833 if (continuous) {
2834 if (starts[i] == *start)
2835 *start += lens[i];
2836 else if (starts[i] + lens[i] >= *stop)
2837 *stop = starts[i];
2838 else
2839 continuous = 0;
2840 /* There will be probably more gaps
2841 than one, so lets check afterwards */
2842 }
2843 } else {
2844 starts[i] = 0;
2845 lens[i] = 0;
2846 }
2847 }
2848}
2849
2850static uint *verify_sun_starts;
2851
2852static int
2853verify_sun_cmp(int *a, int *b) {
2854 if (*a == -1) return 1;
2855 if (*b == -1) return -1;
2856 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2857 return -1;
2858}
2859
2860static void
2861verify_sun(void) {
2862 uint starts[8], lens[8], start, stop;
2863 int i,j,k,starto,endo;
2864 int array[8];
2865
2866 verify_sun_starts = starts;
2867 fetch_sun(starts,lens,&start,&stop);
2868 for (k = 0; k < 7; k++) {
2869 for (i = 0; i < 8; i++) {
2870 if (k && (lens[i] % (heads * sectors))) {
2871 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2872 }
2873 if (lens[i]) {
2874 for (j = 0; j < i; j++)
2875 if (lens[j]) {
2876 if (starts[j] == starts[i]+lens[i]) {
2877 starts[j] = starts[i]; lens[j] += lens[i];
2878 lens[i] = 0;
2879 } else if (starts[i] == starts[j]+lens[j]){
2880 lens[j] += lens[i];
2881 lens[i] = 0;
2882 } else if (!k) {
2883 if (starts[i] < starts[j]+lens[j] &&
2884 starts[j] < starts[i]+lens[i]) {
2885 starto = starts[i];
2886 if (starts[j] > starto)
2887 starto = starts[j];
2888 endo = starts[i]+lens[i];
2889 if (starts[j]+lens[j] < endo)
2890 endo = starts[j]+lens[j];
2891 printf(_("Partition %d overlaps with others in "
2892 "sectors %d-%d\n"), i+1, starto, endo);
2893 }
2894 }
2895 }
2896 }
2897 }
2898 }
2899 for (i = 0; i < 8; i++) {
2900 if (lens[i])
2901 array[i] = i;
2902 else
2903 array[i] = -1;
2904 }
2905 qsort(array,SIZE(array),sizeof(array[0]),
2906 (int (*)(const void *,const void *)) verify_sun_cmp);
2907 if (array[0] == -1) {
2908 printf(_("No partitions defined\n"));
2909 return;
2910 }
2911 stop = cylinders * heads * sectors;
2912 if (starts[array[0]])
2913 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2914 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2915 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2916 }
2917 start = starts[array[i]]+lens[array[i]];
2918 if (start < stop)
2919 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2920}
2921
2922static void
2923add_sun_partition(int n, int sys) {
2924 uint start, stop, stop2;
2925 uint starts[8], lens[8];
2926 int whole_disk = 0;
2927
2928 char mesg[256];
2929 int i, first, last;
2930
2931 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2932 printf(_("Partition %d is already defined. Delete "
2933 "it before re-adding it.\n"), n + 1);
2934 return;
2935 }
2936
2937 fetch_sun(starts,lens,&start,&stop);
2938 if (stop <= start) {
2939 if (n == 2)
2940 whole_disk = 1;
2941 else {
2942 printf(_("Other partitions already cover the whole disk.\nDelete "
2943 "some/shrink them before retry.\n"));
2944 return;
2945 }
2946 }
2947 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2948 for (;;) {
2949 if (whole_disk)
2950 first = read_int(0, 0, 0, 0, mesg);
2951 else
2952 first = read_int(scround(start), scround(stop)+1,
2953 scround(stop), 0, mesg);
2954 if (display_in_cyl_units)
2955 first *= units_per_sector;
2956 else
2957 /* Starting sector has to be properly aligned */
2958 first = (first + heads * sectors - 1) / (heads * sectors);
2959 if (n == 2 && first != 0)
2960 printf ("\
2961It is highly recommended that the third partition covers the whole disk\n\
2962and is of type `Whole disk'\n");
2963 /* ewt asks to add: "don't start a partition at cyl 0"
2964 However, edmundo@rano.demon.co.uk writes:
2965 "In addition to having a Sun partition table, to be able to
2966 boot from the disc, the first partition, /dev/sdX1, must
2967 start at cylinder 0. This means that /dev/sdX1 contains
2968 the partition table and the boot block, as these are the
2969 first two sectors of the disc. Therefore you must be
2970 careful what you use /dev/sdX1 for. In particular, you must
2971 not use a partition starting at cylinder 0 for Linux swap,
2972 as that would overwrite the partition table and the boot
2973 block. You may, however, use such a partition for a UFS
2974 or EXT2 file system, as these file systems leave the first
2975 1024 bytes undisturbed. */
2976 /* On the other hand, one should not use partitions
2977 starting at block 0 in an md, or the label will
2978 be trashed. */
2979 for (i = 0; i < partitions; i++)
2980 if (lens[i] && starts[i] <= first
2981 && starts[i] + lens[i] > first)
2982 break;
2983 if (i < partitions && !whole_disk) {
2984 if (n == 2 && !first) {
2985 whole_disk = 1;
2986 break;
2987 }
2988 printf(_("Sector %d is already allocated\n"), first);
2989 } else
2990 break;
2991 }
2992 stop = cylinders * heads * sectors;
2993 stop2 = stop;
2994 for (i = 0; i < partitions; i++) {
2995 if (starts[i] > first && starts[i] < stop)
2996 stop = starts[i];
2997 }
2998 snprintf(mesg, sizeof(mesg),
2999 _("Last %s or +size or +sizeM or +sizeK"),
3000 str_units(SINGULAR));
3001 if (whole_disk)
3002 last = read_int(scround(stop2), scround(stop2), scround(stop2),
3003 0, mesg);
3004 else if (n == 2 && !first)
3005 last = read_int(scround(first), scround(stop2), scround(stop2),
3006 scround(first), mesg);
3007 else
3008 last = read_int(scround(first), scround(stop), scround(stop),
3009 scround(first), mesg);
3010 if (display_in_cyl_units)
3011 last *= units_per_sector;
3012 if (n == 2 && !first) {
3013 if (last >= stop2) {
3014 whole_disk = 1;
3015 last = stop2;
3016 } else if (last > stop) {
3017 printf (
3018 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
3019 "%d %s covers some other partition. Your entry has been changed\n"
3020 "to %d %s\n"),
3021 scround(last), str_units(SINGULAR),
3022 scround(stop), str_units(SINGULAR));
3023 last = stop;
3024 }
3025 } else if (!whole_disk && last > stop)
3026 last = stop;
3027
3028 if (whole_disk) sys = WHOLE_DISK;
3029 set_sun_partition(n, first, last, sys);
3030}
3031
3032static void
3033sun_delete_partition(int i) {
Eric Andersen040f4402003-07-30 08:40:37 +00003034 unsigned int nsec;
3035
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003036 if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
3037 !sunlabel->partitions[i].start_cylinder &&
Eric Andersen040f4402003-07-30 08:40:37 +00003038 (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003039 == heads * sectors * cylinders)
3040 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3041 "consider leaving this\n"
3042 "partition as Whole disk (5), starting at 0, with %u "
Eric Andersen040f4402003-07-30 08:40:37 +00003043 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003044 sunlabel->infos[i].id = 0;
3045 sunlabel->partitions[i].num_sectors = 0;
3046}
3047
3048static void
3049sun_change_sysid(int i, int sys) {
3050 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3051 read_chars(
3052 _("It is highly recommended that the partition at offset 0\n"
3053 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3054 "there may destroy your partition table and bootblock.\n"
3055 "Type YES if you're very sure you would like that partition\n"
3056 "tagged with 82 (Linux swap): "));
3057 if (strcmp (line_ptr, _("YES\n")))
3058 return;
3059 }
3060 switch (sys) {
3061 case SUNOS_SWAP:
3062 case LINUX_SWAP:
3063 /* swaps are not mountable by default */
3064 sunlabel->infos[i].flags |= 0x01;
3065 break;
3066 default:
3067 /* assume other types are mountable;
3068 user can change it anyway */
3069 sunlabel->infos[i].flags &= ~0x01;
3070 break;
3071 }
3072 sunlabel->infos[i].id = sys;
3073}
3074
3075static void
3076sun_list_table(int xtra) {
3077 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003078
3079 w = strlen(disk_device);
3080 if (xtra)
3081 printf(
3082 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3083 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3084 "%d extra sects/cyl, interleave %d:1\n"
3085 "%s\n"
3086 "Units = %s of %d * 512 bytes\n\n"),
3087 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3088 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3089 SUN_SSWAP16(sunlabel->pcylcount),
3090 SUN_SSWAP16(sunlabel->sparecyl),
3091 SUN_SSWAP16(sunlabel->ilfact),
3092 (char *)sunlabel,
3093 str_units(PLURAL), units_per_sector);
3094 else
3095 printf(
3096 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3097 "Units = %s of %d * 512 bytes\n\n"),
3098 disk_device, heads, sectors, cylinders,
3099 str_units(PLURAL), units_per_sector);
3100
3101 printf(_("%*s Flag Start End Blocks Id System\n"),
3102 w + 1, _("Device"));
3103 for (i = 0 ; i < partitions; i++) {
3104 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003105 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3106 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003107 printf(
3108 "%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3109/* device */ partname(disk_device, i+1, w),
3110/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
3111 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3112/* start */ (long) scround(start),
3113/* end */ (long) scround(start+len),
3114/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
3115/* type id */ sunlabel->infos[i].id,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003116/* type name */ partition_type(sunlabel->infos[i].id));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003117 }
3118 }
3119}
3120
Eric Andersen040f4402003-07-30 08:40:37 +00003121#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3122
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003123static void
3124sun_set_alt_cyl(void) {
3125 sunlabel->nacyl =
3126 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3127 _("Number of alternate cylinders")));
3128}
3129
3130static void
3131sun_set_ncyl(int cyl) {
3132 sunlabel->ncyl = SUN_SSWAP16(cyl);
3133}
3134
3135static void
3136sun_set_xcyl(void) {
3137 sunlabel->sparecyl =
3138 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3139 _("Extra sectors per cylinder")));
3140}
3141
3142static void
3143sun_set_ilfact(void) {
3144 sunlabel->ilfact =
3145 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3146 _("Interleave factor")));
3147}
3148
3149static void
3150sun_set_rspeed(void) {
3151 sunlabel->rspeed =
3152 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3153 _("Rotation speed (rpm)")));
3154}
3155
3156static void
3157sun_set_pcylcount(void) {
3158 sunlabel->pcylcount =
3159 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3160 _("Number of physical cylinders")));
3161}
Eric Andersen040f4402003-07-30 08:40:37 +00003162#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003163
3164static void
3165sun_write_table(void) {
3166 unsigned short *ush = (unsigned short *)sunlabel;
3167 unsigned short csum = 0;
3168
3169 while(ush < (unsigned short *)(&sunlabel->csum))
3170 csum ^= *ush++;
3171 sunlabel->csum = csum;
3172 if (lseek(fd, 0, SEEK_SET) < 0)
3173 fdisk_fatal(unable_to_seek);
3174 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3175 fdisk_fatal(unable_to_write);
3176}
3177#endif /* SUN_LABEL */
3178
3179/* DOS partition types */
3180
3181static const struct systypes i386_sys_types[] = {
3182 {"\x00" "Empty"},
3183 {"\x01" "FAT12"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003184 {"\x04" "FAT16 <32M"},
3185 {"\x05" "Extended"}, /* DOS 3.3+ extended partition */
3186 {"\x06" "FAT16"}, /* DOS 16-bit >=32M */
3187 {"\x07" "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003188 {"\x0a" "OS/2 Boot Manager"},/* OS/2 Boot Manager */
3189 {"\x0b" "Win95 FAT32"},
3190 {"\x0c" "Win95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
3191 {"\x0e" "Win95 FAT16 (LBA)"},
3192 {"\x0f" "Win95 Ext'd (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003193 {"\x11" "Hidden FAT12"},
3194 {"\x12" "Compaq diagnostics"},
3195 {"\x14" "Hidden FAT16 <32M"},
3196 {"\x16" "Hidden FAT16"},
3197 {"\x17" "Hidden HPFS/NTFS"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003198 {"\x1b" "Hidden Win95 FAT32"},
3199 {"\x1c" "Hidden Win95 FAT32 (LBA)"},
3200 {"\x1e" "Hidden Win95 FAT16 (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003201 {"\x3c" "PartitionMagic recovery"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003202 {"\x41" "PPC PReP Boot"},
3203 {"\x42" "SFS"},
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003204 {"\x63" "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3205 {"\x80" "Old Minix"}, /* Minix 1.4a and earlier */
3206 {"\x81" "Minix / old Linux"},/* Minix 1.4b and later */
3207 {"\x82" "Linux swap"}, /* also Solaris */
3208 {"\x83" "Linux"},
3209 {"\x84" "OS/2 hidden C: drive"},
3210 {"\x85" "Linux extended"},
3211 {"\x86" "NTFS volume set"},
3212 {"\x87" "NTFS volume set"},
3213 {"\x8e" "Linux LVM"},
3214 {"\x9f" "BSD/OS"}, /* BSDI */
3215 {"\xa0" "IBM Thinkpad hibernation"},
3216 {"\xa5" "FreeBSD"}, /* various BSD flavours */
3217 {"\xa6" "OpenBSD"},
3218 {"\xa8" "Darwin UFS"},
3219 {"\xa9" "NetBSD"},
3220 {"\xab" "Darwin boot"},
3221 {"\xb7" "BSDI fs"},
3222 {"\xb8" "BSDI swap"},
3223 {"\xbe" "Solaris boot"},
3224 {"\xeb" "BeOS fs"},
3225 {"\xee" "EFI GPT"}, /* Intel EFI GUID Partition Table */
3226 {"\xef" "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
3227 {"\xf0" "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
3228 {"\xf2" "DOS secondary"}, /* DOS 3.3+ secondary */
3229 {"\xfd" "Linux raid autodetect"},/* New (2.2.x) raid partition with
3230 autodetect using persistent
3231 superblock */
3232#ifdef CONFIG_WEIRD_PARTITION_TYPES
3233 {"\x02" "XENIX root"},
3234 {"\x03" "XENIX usr"},
3235 {"\x08" "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3236 {"\x09" "AIX bootable"}, /* AIX data or Coherent */
3237 {"\x10" "OPUS"},
3238 {"\x18" "AST SmartSleep"},
3239 {"\x24" "NEC DOS"},
3240 {"\x39" "Plan 9"},
3241 {"\x40" "Venix 80286"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003242 {"\x4d" "QNX4.x"},
3243 {"\x4e" "QNX4.x 2nd part"},
3244 {"\x4f" "QNX4.x 3rd part"},
3245 {"\x50" "OnTrack DM"},
3246 {"\x51" "OnTrack DM6 Aux1"}, /* (or Novell) */
3247 {"\x52" "CP/M"}, /* CP/M or Microport SysV/AT */
3248 {"\x53" "OnTrack DM6 Aux3"},
3249 {"\x54" "OnTrackDM6"},
3250 {"\x55" "EZ-Drive"},
3251 {"\x56" "Golden Bow"},
3252 {"\x5c" "Priam Edisk"},
3253 {"\x61" "SpeedStor"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003254 {"\x64" "Novell Netware 286"},
3255 {"\x65" "Novell Netware 386"},
3256 {"\x70" "DiskSecure Multi-Boot"},
3257 {"\x75" "PC/IX"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003258 {"\x93" "Amoeba"},
3259 {"\x94" "Amoeba BBT"}, /* (bad block table) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003260 {"\xa7" "NeXTSTEP"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003261 {"\xbb" "Boot Wizard hidden"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003262 {"\xc1" "DRDOS/sec (FAT-12)"},
3263 {"\xc4" "DRDOS/sec (FAT-16 < 32M)"},
3264 {"\xc6" "DRDOS/sec (FAT-16)"},
3265 {"\xc7" "Syrinx"},
3266 {"\xda" "Non-FS data"},
3267 {"\xdb" "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
3268 Concurrent DOS or CTOS */
3269 {"\xde" "Dell Utility"}, /* Dell PowerEdge Server utilities */
3270 {"\xdf" "BootIt"}, /* BootIt EMBRM */
3271 {"\xe1" "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
3272 extended partition */
3273 {"\xe3" "DOS R/O"}, /* DOS R/O or SpeedStor */
3274 {"\xe4" "SpeedStor"}, /* SpeedStor 16-bit FAT extended
3275 partition < 1024 cyl. */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003276 {"\xf1" "SpeedStor"},
3277 {"\xf4" "SpeedStor"}, /* SpeedStor large partition */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003278 {"\xfe" "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
3279 {"\xff" "BBT"}, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003280#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003281 { 0 }
3282};
3283
3284
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003285
3286/* A valid partition table sector ends in 0x55 0xaa */
3287static unsigned int
3288part_table_flag(const char *b) {
3289 return ((uint) b[510]) + (((uint) b[511]) << 8);
3290}
3291
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003292
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003293#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003294static void
3295write_part_table_flag(char *b) {
3296 b[510] = 0x55;
3297 b[511] = 0xaa;
3298}
3299
3300/* start_sect and nr_sects are stored little endian on all machines */
3301/* moreover, they are not aligned correctly */
3302static void
3303store4_little_endian(unsigned char *cp, unsigned int val) {
3304 cp[0] = (val & 0xff);
3305 cp[1] = ((val >> 8) & 0xff);
3306 cp[2] = ((val >> 16) & 0xff);
3307 cp[3] = ((val >> 24) & 0xff);
3308}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003309#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003310
3311static unsigned int
3312read4_little_endian(const unsigned char *cp) {
3313 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3314 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3315}
3316
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003317#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003318static void
3319set_start_sect(struct partition *p, unsigned int start_sect) {
3320 store4_little_endian(p->start4, start_sect);
3321}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003322#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003323
Eric Andersend9261492004-06-28 23:50:31 +00003324static int32_t
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003325get_start_sect(const struct partition *p) {
3326 return read4_little_endian(p->start4);
3327}
3328
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003329#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003330static void
Eric Andersend9261492004-06-28 23:50:31 +00003331set_nr_sects(struct partition *p, int32_t nr_sects) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003332 store4_little_endian(p->size4, nr_sects);
3333}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003334#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003335
Eric Andersend9261492004-06-28 23:50:31 +00003336static int32_t
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003337get_nr_sects(const struct partition *p) {
3338 return read4_little_endian(p->size4);
3339}
3340
3341/* normally O_RDWR, -l option gives O_RDONLY */
3342static int type_open = O_RDWR;
3343
3344
3345static int ext_index, /* the prime extended partition */
3346 listing, /* no aborts for fdisk -l */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003347 dos_compatible_flag = ~0;
3348#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3349static int dos_changed;
3350static int nowarn; /* no warnings for fdisk -l/-s */
3351#endif
3352
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003353
3354
3355static uint user_cylinders, user_heads, user_sectors;
3356static uint pt_heads, pt_sectors;
3357static uint kern_heads, kern_sectors;
3358
Eric Andersend9261492004-06-28 23:50:31 +00003359static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003360
Eric Andersen040f4402003-07-30 08:40:37 +00003361static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003362
3363
3364static jmp_buf listingbuf;
3365
3366static void fdisk_fatal(enum failure why) {
3367 const char *message;
3368
3369 if (listing) {
3370 close(fd);
3371 longjmp(listingbuf, 1);
3372 }
3373
3374 switch (why) {
3375 case unable_to_open:
3376 message = "Unable to open %s\n";
3377 break;
3378 case unable_to_read:
3379 message = "Unable to read %s\n";
3380 break;
3381 case unable_to_seek:
3382 message = "Unable to seek on %s\n";
3383 break;
3384 case unable_to_write:
3385 message = "Unable to write %s\n";
3386 break;
3387 case ioctl_error:
3388 message = "BLKGETSIZE ioctl failed on %s\n";
3389 break;
3390 default:
3391 message = "Fatal error\n";
3392 }
3393
3394 fputc('\n', stderr);
3395 fprintf(stderr, message, disk_device);
3396 exit(1);
3397}
3398
3399static void
Eric Andersend9261492004-06-28 23:50:31 +00003400seek_sector(off_t secno) {
Eric Andersen0a92f352004-03-30 09:21:54 +00003401 off_t offset = secno * sector_size;
3402 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003403 fdisk_fatal(unable_to_seek);
3404}
3405
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003406#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003407static void
Eric Andersend9261492004-06-28 23:50:31 +00003408write_sector(off_t secno, char *buf) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003409 seek_sector(secno);
3410 if (write(fd, buf, sector_size) != sector_size)
3411 fdisk_fatal(unable_to_write);
3412}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003413#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003414
3415/* Allocate a buffer and read a partition table sector */
3416static void
Eric Andersend9261492004-06-28 23:50:31 +00003417read_pte(struct pte *pe, off_t offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003418
3419 pe->offset = offset;
3420 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003421 seek_sector(offset);
3422 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3423 fdisk_fatal(unable_to_read);
3424#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003425 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003426#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003427 pe->part_table = pe->ext_pointer = NULL;
3428}
3429
3430static unsigned int
3431get_partition_start(const struct pte *pe) {
3432 return pe->offset + get_start_sect(pe->part_table);
3433}
3434
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003435#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003436/*
3437 * Avoid warning about DOS partitions when no DOS partition was changed.
3438 * Here a heuristic "is probably dos partition".
3439 * We might also do the opposite and warn in all cases except
3440 * for "is probably nondos partition".
3441 */
3442static int
3443is_dos_partition(int t) {
3444 return (t == 1 || t == 4 || t == 6 ||
3445 t == 0x0b || t == 0x0c || t == 0x0e ||
3446 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3447 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3448 t == 0xc1 || t == 0xc4 || t == 0xc6);
3449}
3450
3451static void
3452menu(void) {
3453#ifdef CONFIG_FEATURE_SUN_LABEL
3454 if (sun_label) {
3455 puts(_("Command action"));
3456 puts(_("\ta\ttoggle a read only flag")); /* sun */
3457 puts(_("\tb\tedit bsd disklabel"));
3458 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3459 puts(_("\td\tdelete a partition"));
3460 puts(_("\tl\tlist known partition types"));
3461 puts(_("\tm\tprint this menu"));
3462 puts(_("\tn\tadd a new partition"));
3463 puts(_("\to\tcreate a new empty DOS partition table"));
3464 puts(_("\tp\tprint the partition table"));
3465 puts(_("\tq\tquit without saving changes"));
3466 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3467 puts(_("\tt\tchange a partition's system id"));
3468 puts(_("\tu\tchange display/entry units"));
3469 puts(_("\tv\tverify the partition table"));
3470 puts(_("\tw\twrite table to disk and exit"));
3471#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3472 puts(_("\tx\textra functionality (experts only)"));
3473#endif
3474 } else
3475#endif
3476#ifdef CONFIG_FEATURE_SGI_LABEL
3477 if (sgi_label) {
3478 puts(_("Command action"));
3479 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3480 puts(_("\tb\tedit bootfile entry")); /* sgi */
3481 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3482 puts(_("\td\tdelete a partition"));
3483 puts(_("\tl\tlist known partition types"));
3484 puts(_("\tm\tprint this menu"));
3485 puts(_("\tn\tadd a new partition"));
3486 puts(_("\to\tcreate a new empty DOS partition table"));
3487 puts(_("\tp\tprint the partition table"));
3488 puts(_("\tq\tquit without saving changes"));
3489 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3490 puts(_("\tt\tchange a partition's system id"));
3491 puts(_("\tu\tchange display/entry units"));
3492 puts(_("\tv\tverify the partition table"));
3493 puts(_("\tw\twrite table to disk and exit"));
3494 } else
3495#endif
3496#ifdef CONFIG_FEATURE_AIX_LABEL
3497 if (aix_label) {
3498 puts(_("Command action"));
3499 puts(_("\tm\tprint this menu"));
3500 puts(_("\to\tcreate a new empty DOS partition table"));
3501 puts(_("\tq\tquit without saving changes"));
3502 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3503 } else
3504#endif
3505 {
3506 puts(_("Command action"));
3507 puts(_("\ta\ttoggle a bootable flag"));
3508 puts(_("\tb\tedit bsd disklabel"));
3509 puts(_("\tc\ttoggle the dos compatibility flag"));
3510 puts(_("\td\tdelete a partition"));
3511 puts(_("\tl\tlist known partition types"));
3512 puts(_("\tm\tprint this menu"));
3513 puts(_("\tn\tadd a new partition"));
3514 puts(_("\to\tcreate a new empty DOS partition table"));
3515 puts(_("\tp\tprint the partition table"));
3516 puts(_("\tq\tquit without saving changes"));
3517 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3518 puts(_("\tt\tchange a partition's system id"));
3519 puts(_("\tu\tchange display/entry units"));
3520 puts(_("\tv\tverify the partition table"));
3521 puts(_("\tw\twrite table to disk and exit"));
3522#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3523 puts(_("\tx\textra functionality (experts only)"));
3524#endif
3525 }
3526}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003527#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3528
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003529
3530#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3531static void
3532xmenu(void) {
3533#ifdef CONFIG_FEATURE_SUN_LABEL
3534 if (sun_label) {
3535 puts(_("Command action"));
3536 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3537 puts(_("\tc\tchange number of cylinders"));
3538 puts(_("\td\tprint the raw data in the partition table"));
3539 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3540 puts(_("\th\tchange number of heads"));
3541 puts(_("\ti\tchange interleave factor")); /*sun*/
3542 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3543 puts(_("\tm\tprint this menu"));
3544 puts(_("\tp\tprint the partition table"));
3545 puts(_("\tq\tquit without saving changes"));
3546 puts(_("\tr\treturn to main menu"));
3547 puts(_("\ts\tchange number of sectors/track"));
3548 puts(_("\tv\tverify the partition table"));
3549 puts(_("\tw\twrite table to disk and exit"));
3550 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
3551 } else
3552#endif
3553#ifdef CONFIG_FEATURE_SGI_LABEL
3554 if (sgi_label) {
3555 puts(_("Command action"));
3556 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3557 puts(_("\tc\tchange number of cylinders"));
3558 puts(_("\td\tprint the raw data in the partition table"));
3559 puts(_("\te\tlist extended partitions")); /* !sun */
3560 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3561 puts(_("\th\tchange number of heads"));
3562 puts(_("\tm\tprint this menu"));
3563 puts(_("\tp\tprint the partition table"));
3564 puts(_("\tq\tquit without saving changes"));
3565 puts(_("\tr\treturn to main menu"));
3566 puts(_("\ts\tchange number of sectors/track"));
3567 puts(_("\tv\tverify the partition table"));
3568 puts(_("\tw\twrite table to disk and exit"));
3569 } else
3570#endif
3571#ifdef CONFIG_FEATURE_AIX_LABEL
3572 if (aix_label) {
3573 puts(_("Command action"));
3574 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3575 puts(_("\tc\tchange number of cylinders"));
3576 puts(_("\td\tprint the raw data in the partition table"));
3577 puts(_("\te\tlist extended partitions")); /* !sun */
3578 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3579 puts(_("\th\tchange number of heads"));
3580 puts(_("\tm\tprint this menu"));
3581 puts(_("\tp\tprint the partition table"));
3582 puts(_("\tq\tquit without saving changes"));
3583 puts(_("\tr\treturn to main menu"));
3584 puts(_("\ts\tchange number of sectors/track"));
3585 puts(_("\tv\tverify the partition table"));
3586 puts(_("\tw\twrite table to disk and exit"));
3587 } else
3588#endif
3589 {
3590 puts(_("Command action"));
3591 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3592 puts(_("\tc\tchange number of cylinders"));
3593 puts(_("\td\tprint the raw data in the partition table"));
3594 puts(_("\te\tlist extended partitions")); /* !sun */
3595 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
3596#ifdef CONFIG_FEATURE_SGI_LABEL
3597 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3598#endif
3599 puts(_("\th\tchange number of heads"));
3600 puts(_("\tm\tprint this menu"));
3601 puts(_("\tp\tprint the partition table"));
3602 puts(_("\tq\tquit without saving changes"));
3603 puts(_("\tr\treturn to main menu"));
3604 puts(_("\ts\tchange number of sectors/track"));
3605 puts(_("\tv\tverify the partition table"));
3606 puts(_("\tw\twrite table to disk and exit"));
3607 }
3608}
3609#endif /* ADVANCED mode */
3610
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003611#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003612static const struct systypes *
3613get_sys_types(void) {
3614 return (
3615#ifdef CONFIG_FEATURE_SUN_LABEL
3616 sun_label ? sun_sys_types :
3617#endif
3618#ifdef CONFIG_FEATURE_SGI_LABEL
3619 sgi_label ? sgi_sys_types :
3620#endif
3621 i386_sys_types);
3622}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003623#else
3624#define get_sys_types() i386_sys_types
3625#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003626
3627static const char *partition_type(unsigned char type)
3628{
3629 int i;
3630 const struct systypes *types = get_sys_types();
3631
3632 for (i=0; types[i].name; i++)
3633 if (types[i].name[0] == type)
3634 return types[i].name + 1;
3635
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003636 return _("Unknown");
3637}
3638
3639
3640#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3641static int
3642get_sysid(int i) {
3643 return (
3644#ifdef CONFIG_FEATURE_SUN_LABEL
3645 sun_label ? sunlabel->infos[i].id :
3646#endif
3647#ifdef CONFIG_FEATURE_SGI_LABEL
3648 sgi_label ? sgi_get_sysid(i) :
3649#endif
3650 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003651}
3652
3653void list_types(const struct systypes *sys)
3654{
3655 uint last[4], done = 0, next = 0, size;
3656 int i;
3657
3658 for (i = 0; sys[i].name; i++);
3659 size = i;
3660
3661 for (i = 3; i >= 0; i--)
3662 last[3 - i] = done += (size + i - done) / (i + 1);
3663 i = done = 0;
3664
3665 do {
3666 printf("%c%2x %-15.15s", i ? ' ' : '\n',
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003667 sys[next].name[0], partition_type(sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003668 next = last[i++] + done;
3669 if (i > 3 || next >= last[i]) {
3670 i = 0;
3671 next = ++done;
3672 }
3673 } while (done < last[0]);
3674 putchar('\n');
3675}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003676#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003677
3678static int
3679is_cleared_partition(const struct partition *p) {
3680 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3681 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3682 get_start_sect(p) || get_nr_sects(p));
3683}
3684
3685static void
3686clear_partition(struct partition *p) {
3687 if (!p)
3688 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003689 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003690}
3691
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003692#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003693static void
Eric Andersend9261492004-06-28 23:50:31 +00003694set_partition(int i, int doext, off_t start, off_t stop, int sysid) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003695 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003696 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003697
3698 if (doext) {
3699 p = ptes[i].ext_pointer;
3700 offset = extended_offset;
3701 } else {
3702 p = ptes[i].part_table;
3703 offset = ptes[i].offset;
3704 }
3705 p->boot_ind = 0;
3706 p->sys_ind = sysid;
3707 set_start_sect(p, start - offset);
3708 set_nr_sects(p, stop - start + 1);
3709 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3710 start = heads*sectors*1024 - 1;
3711 set_hsc(p->head, p->sector, p->cyl, start);
3712 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3713 stop = heads*sectors*1024 - 1;
3714 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3715 ptes[i].changed = 1;
3716}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003717#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003718
3719static int
3720test_c(const char **m, const char *mesg) {
3721 int val = 0;
3722 if (!*m)
3723 fprintf(stderr, _("You must set"));
3724 else {
3725 fprintf(stderr, " %s", *m);
3726 val = 1;
3727 }
3728 *m = mesg;
3729 return val;
3730}
3731
3732static int
3733warn_geometry(void) {
3734 const char *m = NULL;
3735 int prev = 0;
3736
3737 if (!heads)
3738 prev = test_c(&m, _("heads"));
3739 if (!sectors)
3740 prev = test_c(&m, _("sectors"));
3741 if (!cylinders)
3742 prev = test_c(&m, _("cylinders"));
3743 if (!m)
3744 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003745
3746 fprintf(stderr, "%s%s.\n"
3747#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3748 "You can do this from the extra functions menu.\n"
3749#endif
3750 , prev ? _(" and ") : " ", m);
3751
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003752 return 1;
3753}
3754
3755static void update_units(void)
3756{
3757 int cyl_units = heads * sectors;
3758
3759 if (display_in_cyl_units && cyl_units)
3760 units_per_sector = cyl_units;
3761 else
3762 units_per_sector = 1; /* in sectors */
3763}
3764
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003765#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003766static void
3767warn_cylinders(void) {
3768 if (dos_label && cylinders > 1024 && !nowarn)
3769 fprintf(stderr, _("\n"
3770"The number of cylinders for this disk is set to %d.\n"
3771"There is nothing wrong with that, but this is larger than 1024,\n"
3772"and could in certain setups cause problems with:\n"
3773"1) software that runs at boot time (e.g., old versions of LILO)\n"
3774"2) booting and partitioning software from other OSs\n"
3775" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3776 cylinders);
3777}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003778#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003779
3780static void
3781read_extended(int ext) {
3782 int i;
3783 struct pte *pex;
3784 struct partition *p, *q;
3785
3786 ext_index = ext;
3787 pex = &ptes[ext];
3788 pex->ext_pointer = pex->part_table;
3789
3790 p = pex->part_table;
3791 if (!get_start_sect(p)) {
3792 fprintf(stderr,
3793 _("Bad offset in primary extended partition\n"));
3794 return;
3795 }
3796
3797 while (IS_EXTENDED (p->sys_ind)) {
3798 struct pte *pe = &ptes[partitions];
3799
3800 if (partitions >= MAXIMUM_PARTS) {
3801 /* This is not a Linux restriction, but
3802 this program uses arrays of size MAXIMUM_PARTS.
3803 Do not try to `improve' this test. */
3804 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003805#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003806 fprintf(stderr,
3807 _("Warning: deleting partitions after %d\n"),
3808 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003809 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003810#endif
3811 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003812 return;
3813 }
3814
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003815 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003816
3817 if (!extended_offset)
3818 extended_offset = get_start_sect(p);
3819
3820 q = p = pt_offset(pe->sectorbuffer, 0);
3821 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3822 if (IS_EXTENDED (p->sys_ind)) {
3823 if (pe->ext_pointer)
3824 fprintf(stderr,
3825 _("Warning: extra link "
3826 "pointer in partition table"
3827 " %d\n"), partitions + 1);
3828 else
3829 pe->ext_pointer = p;
3830 } else if (p->sys_ind) {
3831 if (pe->part_table)
3832 fprintf(stderr,
3833 _("Warning: ignoring extra "
3834 "data in partition table"
3835 " %d\n"), partitions + 1);
3836 else
3837 pe->part_table = p;
3838 }
3839 }
3840
3841 /* very strange code here... */
3842 if (!pe->part_table) {
3843 if (q != pe->ext_pointer)
3844 pe->part_table = q;
3845 else
3846 pe->part_table = q + 1;
3847 }
3848 if (!pe->ext_pointer) {
3849 if (q != pe->part_table)
3850 pe->ext_pointer = q;
3851 else
3852 pe->ext_pointer = q + 1;
3853 }
3854
3855 p = pe->ext_pointer;
3856 partitions++;
3857 }
3858
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003859#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003860 /* remove empty links */
3861 remove:
3862 for (i = 4; i < partitions; i++) {
3863 struct pte *pe = &ptes[i];
3864
3865 if (!get_nr_sects(pe->part_table) &&
3866 (partitions > 5 || ptes[4].part_table->sys_ind)) {
3867 printf("omitting empty partition (%d)\n", i+1);
3868 delete_partition(i);
3869 goto remove; /* numbering changed */
3870 }
3871 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003872#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003873}
3874
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003875#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003876static void
3877create_doslabel(void) {
3878 int i;
3879
3880 fprintf(stderr,
3881 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3882 "until you decide to write them. After that, of course, the previous\n"
3883 "content won't be recoverable.\n\n"));
3884#ifdef CONFIG_FEATURE_SUN_LABEL
3885 sun_nolabel(); /* otherwise always recognised as sun */
3886#endif
3887#ifdef CONFIG_FEATURE_SGI_LABEL
3888 sgi_nolabel(); /* otherwise always recognised as sgi */
3889#endif
3890#ifdef CONFIG_FEATURE_AIX_LABEL
3891 aix_label = 0;
3892#endif
3893#ifdef CONFIG_FEATURE_OSF_LABEL
3894 osf_label = 0;
3895 possibly_osf_label = 0;
3896#endif
3897 partitions = 4;
3898
3899 for (i = 510-64; i < 510; i++)
3900 MBRbuffer[i] = 0;
3901 write_part_table_flag(MBRbuffer);
3902 extended_offset = 0;
3903 set_all_unchanged();
3904 set_changed(0);
3905 get_boot(create_empty_dos);
3906}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003907#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003908
3909static void
3910get_sectorsize(void) {
3911 if (!user_set_sector_size &&
3912 get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
3913 int arg;
3914 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3915 sector_size = arg;
3916 if (sector_size != DEFAULT_SECTOR_SIZE)
3917 printf(_("Note: sector size is %d (not %d)\n"),
3918 sector_size, DEFAULT_SECTOR_SIZE);
3919 }
3920}
3921
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003922static inline void
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003923get_kernel_geometry(void) {
3924 struct hd_geometry geometry;
3925
3926 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3927 kern_heads = geometry.heads;
3928 kern_sectors = geometry.sectors;
3929 /* never use geometry.cylinders - it is truncated */
3930 }
3931}
3932
3933static void
3934get_partition_table_geometry(void) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003935 const unsigned char *bufp = MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003936 struct partition *p;
3937 int i, h, s, hh, ss;
3938 int first = 1;
3939 int bad = 0;
3940
3941 if (!(valid_part_table_flag(bufp)))
3942 return;
3943
3944 hh = ss = 0;
3945 for (i=0; i<4; i++) {
3946 p = pt_offset(bufp, i);
3947 if (p->sys_ind != 0) {
3948 h = p->end_head + 1;
3949 s = (p->end_sector & 077);
3950 if (first) {
3951 hh = h;
3952 ss = s;
3953 first = 0;
3954 } else if (hh != h || ss != s)
3955 bad = 1;
3956 }
3957 }
3958
3959 if (!first && !bad) {
3960 pt_heads = hh;
3961 pt_sectors = ss;
3962 }
3963}
3964
3965void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003966get_geometry(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003967 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00003968 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003969
3970 get_sectorsize();
3971 sec_fac = sector_size / 512;
3972#ifdef CONFIG_FEATURE_SUN_LABEL
3973 guess_device_type();
3974#endif
3975 heads = cylinders = sectors = 0;
3976 kern_heads = kern_sectors = 0;
3977 pt_heads = pt_sectors = 0;
3978
3979 get_kernel_geometry();
3980 get_partition_table_geometry();
3981
3982 heads = user_heads ? user_heads :
3983 pt_heads ? pt_heads :
3984 kern_heads ? kern_heads : 255;
3985 sectors = user_sectors ? user_sectors :
3986 pt_sectors ? pt_sectors :
3987 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00003988 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
3989 /* got bytes */
3990 } else {
3991 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003992
3993 if (ioctl(fd, BLKGETSIZE, &longsectors))
3994 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00003995 bytes = ((unsigned long long) longsectors) << 9;
3996 }
3997
3998 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003999
4000 sector_offset = 1;
4001 if (dos_compatible_flag)
4002 sector_offset = sectors;
4003
Eric Andersen040f4402003-07-30 08:40:37 +00004004 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004005 if (!cylinders)
4006 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004007}
4008
4009/*
4010 * Read MBR. Returns:
4011 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4012 * 0: found or created label
4013 * 1: I/O error
4014 */
4015int
4016get_boot(enum action what) {
4017 int i;
4018
4019 partitions = 4;
4020
4021 for (i = 0; i < 4; i++) {
4022 struct pte *pe = &ptes[i];
4023
4024 pe->part_table = pt_offset(MBRbuffer, i);
4025 pe->ext_pointer = NULL;
4026 pe->offset = 0;
4027 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004028#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004029 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004030#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004031 }
4032
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004033#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004034 if (what == create_empty_sun && check_sun_label())
4035 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004036#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004037
4038 memset(MBRbuffer, 0, 512);
4039
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004040#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004041 if (what == create_empty_dos)
4042 goto got_dos_table; /* skip reading disk */
4043
4044 if ((fd = open(disk_device, type_open)) < 0) {
4045 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4046 if (what == try_only)
4047 return 1;
4048 fdisk_fatal(unable_to_open);
4049 } else
4050 printf(_("You will not be able to write "
4051 "the partition table.\n"));
4052 }
4053
4054 if (512 != read(fd, MBRbuffer, 512)) {
4055 if (what == try_only)
4056 return 1;
4057 fdisk_fatal(unable_to_read);
4058 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004059#else
4060 if ((fd = open(disk_device, O_RDONLY)) < 0)
4061 return 1;
4062 if (512 != read(fd, MBRbuffer, 512))
4063 return 1;
4064#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004065
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004066 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004067
4068 update_units();
4069
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004070#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004071 if (check_sun_label())
4072 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004073#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004074
4075#ifdef CONFIG_FEATURE_SGI_LABEL
4076 if (check_sgi_label())
4077 return 0;
4078#endif
4079
4080#ifdef CONFIG_FEATURE_AIX_LABEL
4081 if (check_aix_label())
4082 return 0;
4083#endif
4084
4085#ifdef CONFIG_FEATURE_OSF_LABEL
4086 if (check_osf_label()) {
4087 possibly_osf_label = 1;
4088 if (!valid_part_table_flag(MBRbuffer)) {
4089 osf_label = 1;
4090 return 0;
4091 }
4092 printf(_("This disk has both DOS and BSD magic.\n"
4093 "Give the 'b' command to go to BSD mode.\n"));
4094 }
4095#endif
4096
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004097#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004098got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004099#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004100
4101 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004102#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4103 return -1;
4104#else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004105 switch(what) {
4106 case fdisk:
4107 fprintf(stderr,
4108 _("Device contains neither a valid DOS "
4109 "partition table, nor Sun, SGI or OSF "
4110 "disklabel\n"));
4111#ifdef __sparc__
4112#ifdef CONFIG_FEATURE_SUN_LABEL
4113 create_sunlabel();
4114#endif
4115#else
4116 create_doslabel();
4117#endif
4118 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004119 case try_only:
4120 return -1;
4121 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004122#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004123 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004124#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004125 break;
4126 default:
4127 fprintf(stderr, _("Internal error\n"));
4128 exit(1);
4129 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004130#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004131 }
4132
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004133#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004134 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004135#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004136 warn_geometry();
4137
4138 for (i = 0; i < 4; i++) {
4139 struct pte *pe = &ptes[i];
4140
4141 if (IS_EXTENDED (pe->part_table->sys_ind)) {
4142 if (partitions != 4)
4143 fprintf(stderr, _("Ignoring extra extended "
4144 "partition %d\n"), i + 1);
4145 else
4146 read_extended(i);
4147 }
4148 }
4149
4150 for (i = 3; i < partitions; i++) {
4151 struct pte *pe = &ptes[i];
4152
4153 if (!valid_part_table_flag(pe->sectorbuffer)) {
4154 fprintf(stderr,
4155 _("Warning: invalid flag 0x%04x of partition "
4156 "table %d will be corrected by w(rite)\n"),
4157 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004158#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004159 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004160#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004161 }
4162 }
4163
4164 return 0;
4165}
4166
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004167#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004168/*
4169 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4170 * If the user hits Enter, DFLT is returned.
4171 * Answers like +10 are interpreted as offsets from BASE.
4172 *
4173 * There is no default if DFLT is not between LOW and HIGH.
4174 */
4175static uint
4176read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4177{
4178 uint i;
4179 int default_ok = 1;
4180 static char *ms = NULL;
4181 static int mslen = 0;
4182
4183 if (!ms || strlen(mesg)+100 > mslen) {
4184 mslen = strlen(mesg)+200;
4185 ms = xrealloc(ms,mslen);
4186 }
4187
4188 if (dflt < low || dflt > high)
4189 default_ok = 0;
4190
4191 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004192 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004193 mesg, low, high, dflt);
4194 else
Eric Andersen040f4402003-07-30 08:40:37 +00004195 snprintf(ms, mslen, "%s (%u-%u): ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004196 mesg, low, high);
4197
4198 while (1) {
4199 int use_default = default_ok;
4200
4201 /* ask question and read answer */
4202 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4203 && *line_ptr != '-' && *line_ptr != '+')
4204 continue;
4205
Eric Andersen84bdea82004-05-19 10:49:17 +00004206 if (*line_ptr == '+' || *line_ptr == '-') {
Eric Andersenc48d49a2003-07-03 10:02:32 +00004207 int minus = (*line_ptr == '-');
4208 int absolute = 0;
4209
4210 i = atoi(line_ptr+1);
4211
4212 while (isdigit(*++line_ptr))
4213 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004214
Eric Andersenc48d49a2003-07-03 10:02:32 +00004215 switch (*line_ptr) {
4216 case 'c':
4217 case 'C':
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004218 if (!display_in_cyl_units)
4219 i *= heads * sectors;
4220 break;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004221 case 'K':
Eric Andersen040f4402003-07-30 08:40:37 +00004222 absolute = 1024;
4223 break;
4224 case 'k':
Eric Andersenc48d49a2003-07-03 10:02:32 +00004225 absolute = 1000;
4226 break;
4227 case 'm':
4228 case 'M':
4229 absolute = 1000000;
4230 break;
4231 case 'g':
4232 case 'G':
4233 absolute = 1000000000;
4234 break;
4235 default:
4236 break;
4237 }
4238 if (absolute) {
4239 unsigned long long bytes;
4240 unsigned long unit;
4241
4242 bytes = (unsigned long long) i * absolute;
4243 unit = sector_size * units_per_sector;
Eric Andersen84bdea82004-05-19 10:49:17 +00004244 bytes += unit/2; /* round */
Eric Andersenc48d49a2003-07-03 10:02:32 +00004245 bytes /= unit;
4246 i = bytes;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004247 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00004248 if (minus)
4249 i = -i;
4250 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004251 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004252 i = atoi(line_ptr);
4253 while (isdigit(*line_ptr)) {
4254 line_ptr++;
4255 use_default = 0;
4256 }
4257 }
4258 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004259 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004260 if (i >= low && i <= high)
4261 break;
4262 else
4263 printf(_("Value out of range.\n"));
4264 }
4265 return i;
4266}
4267
4268int
4269get_partition(int warn, int max) {
4270 struct pte *pe;
4271 int i;
4272
4273 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4274 pe = &ptes[i];
4275
4276 if (warn) {
4277 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4278#ifdef CONFIG_FEATURE_SUN_LABEL
4279 || (sun_label &&
4280 (!sunlabel->partitions[i].num_sectors ||
4281 !sunlabel->infos[i].id))
4282#endif
4283#ifdef CONFIG_FEATURE_SGI_LABEL
4284 || (sgi_label && (!sgi_get_num_sectors(i)))
4285#endif
4286 )
4287 fprintf(stderr,
4288 _("Warning: partition %d has empty type\n"),
4289 i+1);
4290 }
4291 return i;
4292}
4293
4294static int
4295get_existing_partition(int warn, int max) {
4296 int pno = -1;
4297 int i;
4298
4299 for (i = 0; i < max; i++) {
4300 struct pte *pe = &ptes[i];
4301 struct partition *p = pe->part_table;
4302
4303 if (p && !is_cleared_partition(p)) {
4304 if (pno >= 0)
4305 goto not_unique;
4306 pno = i;
4307 }
4308 }
4309 if (pno >= 0) {
4310 printf(_("Selected partition %d\n"), pno+1);
4311 return pno;
4312 }
4313 printf(_("No partition is defined yet!\n"));
4314 return -1;
4315
4316 not_unique:
4317 return get_partition(warn, max);
4318}
4319
4320static int
4321get_nonexisting_partition(int warn, int max) {
4322 int pno = -1;
4323 int i;
4324
4325 for (i = 0; i < max; i++) {
4326 struct pte *pe = &ptes[i];
4327 struct partition *p = pe->part_table;
4328
4329 if (p && is_cleared_partition(p)) {
4330 if (pno >= 0)
4331 goto not_unique;
4332 pno = i;
4333 }
4334 }
4335 if (pno >= 0) {
4336 printf(_("Selected partition %d\n"), pno+1);
4337 return pno;
4338 }
4339 printf(_("All primary partitions have been defined already!\n"));
4340 return -1;
4341
4342 not_unique:
4343 return get_partition(warn, max);
4344}
4345
4346
4347void change_units(void)
4348{
4349 display_in_cyl_units = !display_in_cyl_units;
4350 update_units();
4351 printf(_("Changing display/entry units to %s\n"),
4352 str_units(PLURAL));
4353}
4354
4355static void
4356toggle_active(int i) {
4357 struct pte *pe = &ptes[i];
4358 struct partition *p = pe->part_table;
4359
4360 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
4361 fprintf(stderr,
4362 _("WARNING: Partition %d is an extended partition\n"),
4363 i + 1);
4364 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4365 pe->changed = 1;
4366}
4367
4368static void
4369toggle_dos_compatibility_flag(void) {
4370 dos_compatible_flag = ~dos_compatible_flag;
4371 if (dos_compatible_flag) {
4372 sector_offset = sectors;
4373 printf(_("DOS Compatibility flag is set\n"));
4374 }
4375 else {
4376 sector_offset = 1;
4377 printf(_("DOS Compatibility flag is not set\n"));
4378 }
4379}
4380
4381static void
4382delete_partition(int i) {
4383 struct pte *pe = &ptes[i];
4384 struct partition *p = pe->part_table;
4385 struct partition *q = pe->ext_pointer;
4386
4387/* Note that for the fifth partition (i == 4) we don't actually
4388 * decrement partitions.
4389 */
4390
4391 if (warn_geometry())
4392 return; /* C/H/S not set */
4393 pe->changed = 1;
4394
4395#ifdef CONFIG_FEATURE_SUN_LABEL
4396 if (sun_label) {
4397 sun_delete_partition(i);
4398 return;
4399 }
4400#endif
4401#ifdef CONFIG_FEATURE_SGI_LABEL
4402 if (sgi_label) {
4403 sgi_delete_partition(i);
4404 return;
4405 }
4406#endif
4407
4408 if (i < 4) {
4409 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
4410 partitions = 4;
4411 ptes[ext_index].ext_pointer = NULL;
4412 extended_offset = 0;
4413 }
4414 clear_partition(p);
4415 return;
4416 }
4417
4418 if (!q->sys_ind && i > 4) {
4419 /* the last one in the chain - just delete */
4420 --partitions;
4421 --i;
4422 clear_partition(ptes[i].ext_pointer);
4423 ptes[i].changed = 1;
4424 } else {
4425 /* not the last one - further ones will be moved down */
4426 if (i > 4) {
4427 /* delete this link in the chain */
4428 p = ptes[i-1].ext_pointer;
4429 *p = *q;
4430 set_start_sect(p, get_start_sect(q));
4431 set_nr_sects(p, get_nr_sects(q));
4432 ptes[i-1].changed = 1;
4433 } else if (partitions > 5) { /* 5 will be moved to 4 */
4434 /* the first logical in a longer chain */
4435 pe = &ptes[5];
4436
4437 if (pe->part_table) /* prevent SEGFAULT */
4438 set_start_sect(pe->part_table,
4439 get_partition_start(pe) -
4440 extended_offset);
4441 pe->offset = extended_offset;
4442 pe->changed = 1;
4443 }
4444
4445 if (partitions > 5) {
4446 partitions--;
4447 while (i < partitions) {
4448 ptes[i] = ptes[i+1];
4449 i++;
4450 }
4451 } else
4452 /* the only logical: clear only */
4453 clear_partition(ptes[i].part_table);
4454 }
4455}
4456
4457static void
4458change_sysid(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004459 int i, sys, origsys;
4460 struct partition *p;
4461
Eric Andersen040f4402003-07-30 08:40:37 +00004462#ifdef CONFIG_FEATURE_SGI_LABEL
4463 /* If sgi_label then don't use get_existing_partition,
4464 let the user select a partition, since get_existing_partition()
4465 only works for Linux like partition tables. */
4466 if (!sgi_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004467 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004468 } else {
4469 i = get_partition(0, partitions);
4470 }
4471#else
4472 i = get_existing_partition(0, partitions);
4473#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004474 if (i == -1)
4475 return;
4476 p = ptes[i].part_table;
4477 origsys = sys = get_sysid(i);
4478
4479 /* if changing types T to 0 is allowed, then
4480 the reverse change must be allowed, too */
4481 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4482 printf(_("Partition %d does not exist yet!\n"), i + 1);
4483 else while (1) {
4484 sys = read_hex (get_sys_types());
4485
4486 if (!sys && !sgi_label && !sun_label) {
4487 printf(_("Type 0 means free space to many systems\n"
4488 "(but not to Linux). Having partitions of\n"
4489 "type 0 is probably unwise. You can delete\n"
4490 "a partition using the `d' command.\n"));
4491 /* break; */
4492 }
4493
4494 if (!sun_label && !sgi_label) {
4495 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
4496 printf(_("You cannot change a partition into"
4497 " an extended one or vice versa\n"
4498 "Delete it first.\n"));
4499 break;
4500 }
4501 }
4502
4503 if (sys < 256) {
4504#ifdef CONFIG_FEATURE_SUN_LABEL
4505 if (sun_label && i == 2 && sys != WHOLE_DISK)
4506 printf(_("Consider leaving partition 3 "
4507 "as Whole disk (5),\n"
4508 "as SunOS/Solaris expects it and "
4509 "even Linux likes it.\n\n"));
4510#endif
4511#ifdef CONFIG_FEATURE_SGI_LABEL
4512 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4513 || (i == 8 && sys != 0)))
4514 printf(_("Consider leaving partition 9 "
4515 "as volume header (0),\nand "
4516 "partition 11 as entire volume (6)"
4517 "as IRIX expects it.\n\n"));
4518#endif
4519 if (sys == origsys)
4520 break;
4521#ifdef CONFIG_FEATURE_SUN_LABEL
4522 if (sun_label) {
4523 sun_change_sysid(i, sys);
4524 } else
4525#endif
4526#ifdef CONFIG_FEATURE_SGI_LABEL
4527 if (sgi_label) {
4528 sgi_change_sysid(i, sys);
4529 } else
4530#endif
4531 p->sys_ind = sys;
4532 printf (_("Changed system type of partition %d "
4533 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004534 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004535 ptes[i].changed = 1;
4536 if (is_dos_partition(origsys) ||
4537 is_dos_partition(sys))
4538 dos_changed = 1;
4539 break;
4540 }
4541 }
4542}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004543#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4544
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004545
4546/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4547 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4548 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4549 * Lubkin Oct. 1991). */
4550
4551static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
4552 int spc = heads * sectors;
4553
4554 *c = ls / spc;
4555 ls = ls % spc;
4556 *h = ls / sectors;
4557 *s = ls % sectors + 1; /* sectors count from 1 */
4558}
4559
4560static void check_consistency(const struct partition *p, int partition) {
4561 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4562 uint pec, peh, pes; /* physical ending c, h, s */
4563 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4564 uint lec, leh, les; /* logical ending c, h, s */
4565
4566 if (!heads || !sectors || (partition >= 4))
4567 return; /* do not check extended partitions */
4568
4569/* physical beginning c, h, s */
4570 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4571 pbh = p->head;
4572 pbs = p->sector & 0x3f;
4573
4574/* physical ending c, h, s */
4575 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4576 peh = p->end_head;
4577 pes = p->end_sector & 0x3f;
4578
4579/* compute logical beginning (c, h, s) */
4580 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4581
4582/* compute logical ending (c, h, s) */
4583 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4584
4585/* Same physical / logical beginning? */
4586 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4587 printf(_("Partition %d has different physical/logical "
4588 "beginnings (non-Linux?):\n"), partition + 1);
4589 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4590 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4591 }
4592
4593/* Same physical / logical ending? */
4594 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4595 printf(_("Partition %d has different physical/logical "
4596 "endings:\n"), partition + 1);
4597 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4598 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4599 }
4600
4601#if 0
4602/* Beginning on cylinder boundary? */
4603 if (pbh != !pbc || pbs != 1) {
4604 printf(_("Partition %i does not start on cylinder "
4605 "boundary:\n"), partition + 1);
4606 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4607 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4608 }
4609#endif
4610
4611/* Ending on cylinder boundary? */
4612 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004613 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004614 partition + 1);
4615#if 0
4616 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4617 printf(_("should be (%d, %d, %d)\n"),
4618 pec, heads - 1, sectors);
4619#endif
4620 }
4621}
4622
4623static void
4624list_disk_geometry(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00004625 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004626 long megabytes = bytes/1000000;
4627
4628 if (megabytes < 10000)
4629 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4630 disk_device, megabytes, bytes);
4631 else
4632 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4633 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4634 printf(_("%d heads, %d sectors/track, %d cylinders"),
4635 heads, sectors, cylinders);
4636 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004637 printf(_(", total %llu sectors"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004638 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004639 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004640 str_units(PLURAL),
4641 units_per_sector, sector_size, units_per_sector * sector_size);
4642}
4643
4644/*
4645 * Check whether partition entries are ordered by their starting positions.
4646 * Return 0 if OK. Return i if partition i should have been earlier.
4647 * Two separate checks: primary and logical partitions.
4648 */
4649static int
4650wrong_p_order(int *prev) {
4651 const struct pte *pe;
4652 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004653 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004654 int i, last_i = 0;
4655
4656 for (i = 0 ; i < partitions; i++) {
4657 if (i == 4) {
4658 last_i = 4;
4659 last_p_start_pos = 0;
4660 }
4661 pe = &ptes[i];
4662 if ((p = pe->part_table)->sys_ind) {
4663 p_start_pos = get_partition_start(pe);
4664
4665 if (last_p_start_pos > p_start_pos) {
4666 if (prev)
4667 *prev = last_i;
4668 return i;
4669 }
4670
4671 last_p_start_pos = p_start_pos;
4672 last_i = i;
4673 }
4674 }
4675 return 0;
4676}
4677
4678#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4679/*
4680 * Fix the chain of logicals.
4681 * extended_offset is unchanged, the set of sectors used is unchanged
4682 * The chain is sorted so that sectors increase, and so that
4683 * starting sectors increase.
4684 *
4685 * After this it may still be that cfdisk doesnt like the table.
4686 * (This is because cfdisk considers expanded parts, from link to
4687 * end of partition, and these may still overlap.)
4688 * Now
4689 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4690 * may help.
4691 */
4692static void
4693fix_chain_of_logicals(void) {
4694 int j, oj, ojj, sj, sjj;
4695 struct partition *pj,*pjj,tmp;
4696
4697 /* Stage 1: sort sectors but leave sector of part 4 */
4698 /* (Its sector is the global extended_offset.) */
4699 stage1:
4700 for (j = 5; j < partitions-1; j++) {
4701 oj = ptes[j].offset;
4702 ojj = ptes[j+1].offset;
4703 if (oj > ojj) {
4704 ptes[j].offset = ojj;
4705 ptes[j+1].offset = oj;
4706 pj = ptes[j].part_table;
4707 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4708 pjj = ptes[j+1].part_table;
4709 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4710 set_start_sect(ptes[j-1].ext_pointer,
4711 ojj-extended_offset);
4712 set_start_sect(ptes[j].ext_pointer,
4713 oj-extended_offset);
4714 goto stage1;
4715 }
4716 }
4717
4718 /* Stage 2: sort starting sectors */
4719 stage2:
4720 for (j = 4; j < partitions-1; j++) {
4721 pj = ptes[j].part_table;
4722 pjj = ptes[j+1].part_table;
4723 sj = get_start_sect(pj);
4724 sjj = get_start_sect(pjj);
4725 oj = ptes[j].offset;
4726 ojj = ptes[j+1].offset;
4727 if (oj+sj > ojj+sjj) {
4728 tmp = *pj;
4729 *pj = *pjj;
4730 *pjj = tmp;
4731 set_start_sect(pj, ojj+sjj-oj);
4732 set_start_sect(pjj, oj+sj-ojj);
4733 goto stage2;
4734 }
4735 }
4736
4737 /* Probably something was changed */
4738 for (j = 4; j < partitions; j++)
4739 ptes[j].changed = 1;
4740}
4741
4742
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004743static void
4744fix_partition_table_order(void) {
4745 struct pte *pei, *pek;
4746 int i,k;
4747
4748 if (!wrong_p_order(NULL)) {
4749 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4750 return;
4751 }
4752
4753 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4754 /* partition i should have come earlier, move it */
4755 /* We have to move data in the MBR */
4756 struct partition *pi, *pk, *pe, pbuf;
4757 pei = &ptes[i];
4758 pek = &ptes[k];
4759
4760 pe = pei->ext_pointer;
4761 pei->ext_pointer = pek->ext_pointer;
4762 pek->ext_pointer = pe;
4763
4764 pi = pei->part_table;
4765 pk = pek->part_table;
4766
4767 memmove(&pbuf, pi, sizeof(struct partition));
4768 memmove(pi, pk, sizeof(struct partition));
4769 memmove(pk, &pbuf, sizeof(struct partition));
4770
4771 pei->changed = pek->changed = 1;
4772 }
4773
4774 if (i)
4775 fix_chain_of_logicals();
4776
4777 printf("Done.\n");
4778
4779}
4780#endif
4781
4782static void
4783list_table(int xtra) {
4784 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004785 int i, w;
4786
4787#ifdef CONFIG_FEATURE_SUN_LABEL
4788 if (sun_label) {
4789 sun_list_table(xtra);
4790 return;
4791 }
4792#endif
4793
4794#ifdef CONFIG_FEATURE_SGI_LABEL
4795 if (sgi_label) {
4796 sgi_list_table(xtra);
4797 return;
4798 }
4799#endif
4800
4801 list_disk_geometry();
4802
4803#ifdef CONFIG_FEATURE_OSF_LABEL
4804 if (osf_label) {
4805 xbsd_print_disklabel(xtra);
4806 return;
4807 }
4808#endif
4809
4810 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4811 but if the device name ends in a digit, say /dev/foo1,
4812 then the partition is called /dev/foo1p3. */
4813 w = strlen(disk_device);
4814 if (w && isdigit(disk_device[w-1]))
4815 w++;
4816 if (w < 5)
4817 w = 5;
4818
4819 printf(_("%*s Boot Start End Blocks Id System\n"),
4820 w+1, _("Device"));
4821
4822 for (i = 0; i < partitions; i++) {
4823 const struct pte *pe = &ptes[i];
4824
4825 p = pe->part_table;
4826 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004827 off_t psects = get_nr_sects(p);
4828 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004829 unsigned int podd = 0;
4830
4831 if (sector_size < 1024) {
4832 pblocks /= (1024 / sector_size);
4833 podd = psects % (1024 / sector_size);
4834 }
4835 if (sector_size > 1024)
4836 pblocks *= (sector_size / 1024);
4837 printf(
Eric Andersend9261492004-06-28 23:50:31 +00004838 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004839 partname(disk_device, i+1, w+2),
4840/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4841 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004842/* start */ (unsigned long long) cround(get_partition_start(pe)),
4843/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004844 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004845/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004846/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004847/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004848 check_consistency(p, i);
4849 }
4850 }
4851
4852 /* Is partition table in disk order? It need not be, but... */
4853 /* partition table entries are not checked for correct order if this
4854 is a sgi, sun or aix labeled disk... */
4855 if (dos_label && wrong_p_order(NULL)) {
4856 printf(_("\nPartition table entries are not in disk order\n"));
4857 }
4858}
4859
4860#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4861static void
4862x_list_table(int extend) {
4863 const struct pte *pe;
4864 const struct partition *p;
4865 int i;
4866
4867 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4868 disk_device, heads, sectors, cylinders);
4869 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4870 for (i = 0 ; i < partitions; i++) {
4871 pe = &ptes[i];
4872 p = (extend ? pe->ext_pointer : pe->part_table);
4873 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004874 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004875 i + 1, p->boot_ind, p->head,
4876 sector(p->sector),
4877 cylinder(p->sector, p->cyl), p->end_head,
4878 sector(p->end_sector),
4879 cylinder(p->end_sector, p->end_cyl),
4880 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4881 if (p->sys_ind)
4882 check_consistency(p, i);
4883 }
4884 }
4885}
4886#endif
4887
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004888#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004889static void
Eric Andersend9261492004-06-28 23:50:31 +00004890fill_bounds(off_t *first, off_t *last) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004891 int i;
4892 const struct pte *pe = &ptes[0];
4893 const struct partition *p;
4894
4895 for (i = 0; i < partitions; pe++,i++) {
4896 p = pe->part_table;
4897 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
4898 first[i] = 0xffffffff;
4899 last[i] = 0;
4900 } else {
4901 first[i] = get_partition_start(pe);
4902 last[i] = first[i] + get_nr_sects(p) - 1;
4903 }
4904 }
4905}
4906
4907static void
Eric Andersend9261492004-06-28 23:50:31 +00004908check(int n, uint h, uint s, uint c, off_t start) {
4909 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004910
4911 real_s = sector(s) - 1;
4912 real_c = cylinder(s, c);
4913 total = (real_c * sectors + real_s) * heads + h;
4914 if (!total)
4915 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4916 if (h >= heads)
4917 fprintf(stderr,
4918 _("Partition %d: head %d greater than maximum %d\n"),
4919 n, h + 1, heads);
4920 if (real_s >= sectors)
4921 fprintf(stderr, _("Partition %d: sector %d greater than "
4922 "maximum %d\n"), n, s, sectors);
4923 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00004924 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
4925 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004926 if (cylinders <= 1024 && start != total)
4927 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00004928 _("Partition %d: previous sectors %llu disagrees with "
4929 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004930}
4931
4932static void
4933verify(void) {
4934 int i, j;
4935 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00004936 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004937 struct partition *p;
4938
4939 if (warn_geometry())
4940 return;
4941
4942#ifdef CONFIG_FEATURE_SUN_LABEL
4943 if (sun_label) {
4944 verify_sun();
4945 return;
4946 }
4947#endif
4948#ifdef CONFIG_FEATURE_SGI_LABEL
4949 if (sgi_label) {
4950 verify_sgi(1);
4951 return;
4952 }
4953#endif
4954
4955 fill_bounds(first, last);
4956 for (i = 0; i < partitions; i++) {
4957 struct pte *pe = &ptes[i];
4958
4959 p = pe->part_table;
4960 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
4961 check_consistency(p, i);
4962 if (get_partition_start(pe) < first[i])
4963 printf(_("Warning: bad start-of-data in "
4964 "partition %d\n"), i + 1);
4965 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
4966 last[i]);
4967 total += last[i] + 1 - first[i];
4968 for (j = 0; j < i; j++)
4969 if ((first[i] >= first[j] && first[i] <= last[j])
4970 || ((last[i] <= last[j] && last[i] >= first[j]))) {
4971 printf(_("Warning: partition %d overlaps "
4972 "partition %d.\n"), j + 1, i + 1);
4973 total += first[i] >= first[j] ?
4974 first[i] : first[j];
4975 total -= last[i] <= last[j] ?
4976 last[i] : last[j];
4977 }
4978 }
4979 }
4980
4981 if (extended_offset) {
4982 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00004983 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004984 get_nr_sects(pex->part_table) - 1;
4985
4986 for (i = 4; i < partitions; i++) {
4987 total++;
4988 p = ptes[i].part_table;
4989 if (!p->sys_ind) {
4990 if (i != 4 || i + 1 < partitions)
4991 printf(_("Warning: partition %d "
4992 "is empty\n"), i + 1);
4993 }
4994 else if (first[i] < extended_offset ||
4995 last[i] > e_last)
4996 printf(_("Logical partition %d not entirely in "
4997 "partition %d\n"), i + 1, ext_index + 1);
4998 }
4999 }
5000
5001 if (total > heads * sectors * cylinders)
5002 printf(_("Total allocated sectors %d greater than the maximum "
5003 "%d\n"), total, heads * sectors * cylinders);
5004 else if ((total = heads * sectors * cylinders - total) != 0)
5005 printf(_("%d unallocated sectors\n"), total);
5006}
5007
5008static void
5009add_partition(int n, int sys) {
5010 char mesg[256]; /* 48 does not suffice in Japanese */
5011 int i, readed = 0;
5012 struct partition *p = ptes[n].part_table;
5013 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005014 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005015 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005016 first[partitions], last[partitions];
5017
5018 if (p && p->sys_ind) {
5019 printf(_("Partition %d is already defined. Delete "
5020 "it before re-adding it.\n"), n + 1);
5021 return;
5022 }
5023 fill_bounds(first, last);
5024 if (n < 4) {
5025 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005026 if (display_in_cyl_units || !total_number_of_sectors)
5027 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005028 else
Eric Andersen040f4402003-07-30 08:40:37 +00005029 llimit = total_number_of_sectors - 1;
5030 limit = llimit;
5031 if (limit != llimit)
5032 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005033 if (extended_offset) {
5034 first[ext_index] = extended_offset;
5035 last[ext_index] = get_start_sect(q) +
5036 get_nr_sects(q) - 1;
5037 }
5038 } else {
5039 start = extended_offset + sector_offset;
5040 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5041 }
5042 if (display_in_cyl_units)
5043 for (i = 0; i < partitions; i++)
5044 first[i] = (cround(first[i]) - 1) * units_per_sector;
5045
5046 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5047 do {
5048 temp = start;
5049 for (i = 0; i < partitions; i++) {
5050 int lastplusoff;
5051
5052 if (start == ptes[i].offset)
5053 start += sector_offset;
5054 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
5055 if (start >= first[i] && start <= lastplusoff)
5056 start = lastplusoff + 1;
5057 }
5058 if (start > limit)
5059 break;
5060 if (start >= temp+units_per_sector && readed) {
Eric Andersend9261492004-06-28 23:50:31 +00005061 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005062 temp = start;
5063 readed = 0;
5064 }
5065 if (!readed && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005066 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005067
5068 saved_start = start;
5069 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5070 0, mesg);
5071 if (display_in_cyl_units) {
5072 start = (start - 1) * units_per_sector;
5073 if (start < saved_start) start = saved_start;
5074 }
5075 readed = 1;
5076 }
5077 } while (start != temp || !readed);
5078 if (n > 4) { /* NOT for fifth partition */
5079 struct pte *pe = &ptes[n];
5080
5081 pe->offset = start - sector_offset;
5082 if (pe->offset == extended_offset) { /* must be corrected */
5083 pe->offset++;
5084 if (sector_offset == 1)
5085 start++;
5086 }
5087 }
5088
5089 for (i = 0; i < partitions; i++) {
5090 struct pte *pe = &ptes[i];
5091
5092 if (start < pe->offset && limit >= pe->offset)
5093 limit = pe->offset - 1;
5094 if (start < first[i] && limit >= first[i])
5095 limit = first[i] - 1;
5096 }
5097 if (start > limit) {
5098 printf(_("No free sectors available\n"));
5099 if (n > 4)
5100 partitions--;
5101 return;
5102 }
5103 if (cround(start) == cround(limit)) {
5104 stop = limit;
5105 } else {
5106 snprintf(mesg, sizeof(mesg),
5107 _("Last %s or +size or +sizeM or +sizeK"),
5108 str_units(SINGULAR));
5109 stop = read_int(cround(start), cround(limit), cround(limit),
5110 cround(start), mesg);
5111 if (display_in_cyl_units) {
5112 stop = stop * units_per_sector - 1;
5113 if (stop >limit)
5114 stop = limit;
5115 }
5116 }
5117
5118 set_partition(n, 0, start, stop, sys);
5119 if (n > 4)
5120 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5121
5122 if (IS_EXTENDED (sys)) {
5123 struct pte *pe4 = &ptes[4];
5124 struct pte *pen = &ptes[n];
5125
5126 ext_index = n;
5127 pen->ext_pointer = p;
5128 pe4->offset = extended_offset = start;
5129 pe4->sectorbuffer = xcalloc(1, sector_size);
5130 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5131 pe4->ext_pointer = pe4->part_table + 1;
5132 pe4->changed = 1;
5133 partitions = 5;
5134 }
5135}
5136
5137static void
5138add_logical(void) {
5139 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5140 struct pte *pe = &ptes[partitions];
5141
5142 pe->sectorbuffer = xcalloc(1, sector_size);
5143 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5144 pe->ext_pointer = pe->part_table + 1;
5145 pe->offset = 0;
5146 pe->changed = 1;
5147 partitions++;
5148 }
5149 add_partition(partitions - 1, LINUX_NATIVE);
5150}
5151
5152static void
5153new_partition(void) {
5154 int i, free_primary = 0;
5155
5156 if (warn_geometry())
5157 return;
5158
5159#ifdef CONFIG_FEATURE_SUN_LABEL
5160 if (sun_label) {
5161 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5162 return;
5163 }
5164#endif
5165#ifdef CONFIG_FEATURE_SGI_LABEL
5166 if (sgi_label) {
5167 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5168 return;
5169 }
5170#endif
5171#ifdef CONFIG_FEATURE_AIX_LABEL
5172 if (aix_label) {
5173 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5174 "\n\tIf you want to add DOS-type partitions, create"
5175 "\n\ta new empty DOS partition table first. (Use o.)"
5176 "\n\tWARNING: "
5177 "This will destroy the present disk contents.\n"));
5178 return;
5179 }
5180#endif
5181
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005182 for (i = 0; i < 4; i++)
5183 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005184
5185 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005186 printf(_("The maximum number of partitions has been created\n"));
5187 return;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005188 }
5189
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005190 if (!free_primary) {
5191 if (extended_offset)
5192 add_logical();
5193 else
5194 printf(_("You must delete some partition and add "
5195 "an extended partition first\n"));
5196 } else {
5197 char c, line[LINE_LENGTH];
5198 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5199 "partition (1-4)\n",
5200 "Command action", (extended_offset ?
5201 "l logical (5 or over)" : "e extended"));
5202 while (1) {
5203 if ((c = read_char(line)) == 'p' || c == 'P') {
5204 i = get_nonexisting_partition(0, 4);
5205 if (i >= 0)
5206 add_partition(i, LINUX_NATIVE);
5207 return;
5208 }
5209 else if (c == 'l' && extended_offset) {
5210 add_logical();
5211 return;
5212 }
5213 else if (c == 'e' && !extended_offset) {
5214 i = get_nonexisting_partition(0, 4);
5215 if (i >= 0)
5216 add_partition(i, EXTENDED);
5217 return;
5218 }
5219 else
5220 printf(_("Invalid partition number "
5221 "for type `%c'\n"), c);
5222 }
5223 }
5224}
5225
5226static void
5227write_table(void) {
5228 int i;
5229
5230 if (dos_label) {
5231 for (i=0; i<3; i++)
5232 if (ptes[i].changed)
5233 ptes[3].changed = 1;
5234 for (i = 3; i < partitions; i++) {
5235 struct pte *pe = &ptes[i];
5236
5237 if (pe->changed) {
5238 write_part_table_flag(pe->sectorbuffer);
5239 write_sector(pe->offset, pe->sectorbuffer);
5240 }
5241 }
5242 }
5243#ifdef CONFIG_FEATURE_SGI_LABEL
5244 else if (sgi_label) {
5245 /* no test on change? the printf below might be mistaken */
5246 sgi_write_table();
5247 }
5248#endif
5249#ifdef CONFIG_FEATURE_SUN_LABEL
5250 else if (sun_label) {
5251 int needw = 0;
5252
5253 for (i=0; i<8; i++)
5254 if (ptes[i].changed)
5255 needw = 1;
5256 if (needw)
5257 sun_write_table();
5258 }
5259#endif
5260
5261 printf(_("The partition table has been altered!\n\n"));
5262 reread_partition_table(1);
5263}
5264
5265void
5266reread_partition_table(int leave) {
5267 int error = 0;
5268 int i;
5269
5270 printf(_("Calling ioctl() to re-read partition table.\n"));
5271 sync();
5272 sleep(2);
5273 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5274 error = errno;
5275 } else {
5276 /* some kernel versions (1.2.x) seem to have trouble
5277 rereading the partition table, but if asked to do it
5278 twice, the second time works. - biro@yggdrasil.com */
5279 sync();
5280 sleep(2);
5281 if ((i = ioctl(fd, BLKRRPART)) != 0)
5282 error = errno;
5283 }
5284
5285 if (i) {
5286 printf(_("\nWARNING: Re-reading the partition table "
5287 "failed with error %d: %s.\n"
5288 "The kernel still uses the old table.\n"
5289 "The new table will be used "
5290 "at the next reboot.\n"),
5291 error, strerror(error));
5292 }
5293
5294 if (dos_changed)
5295 printf(
5296 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5297 "partitions, please see the fdisk manual page for additional\n"
5298 "information.\n"));
5299
5300 if (leave) {
5301 close(fd);
5302
5303 printf(_("Syncing disks.\n"));
5304 sync();
5305 sleep(4); /* for sync() */
5306 exit(!!i);
5307 }
5308}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005309#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005310
5311#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5312#define MAX_PER_LINE 16
5313static void
5314print_buffer(char pbuffer[]) {
5315 int i,
5316 l;
5317
5318 for (i = 0, l = 0; i < sector_size; i++, l++) {
5319 if (l == 0)
5320 printf("0x%03X:", i);
5321 printf(" %02X", (unsigned char) pbuffer[i]);
5322 if (l == MAX_PER_LINE - 1) {
5323 printf("\n");
5324 l = -1;
5325 }
5326 }
5327 if (l > 0)
5328 printf("\n");
5329 printf("\n");
5330}
5331
5332
5333static void
5334print_raw(void) {
5335 int i;
5336
5337 printf(_("Device: %s\n"), disk_device);
5338#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5339 if (sun_label || sgi_label)
5340 print_buffer(MBRbuffer);
5341 else
5342#endif
5343 for (i = 3; i < partitions; i++)
5344 print_buffer(ptes[i].sectorbuffer);
5345}
5346
5347static void
5348move_begin(int i) {
5349 struct pte *pe = &ptes[i];
5350 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005351 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005352
5353 if (warn_geometry())
5354 return;
5355 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
5356 printf(_("Partition %d has no data area\n"), i + 1);
5357 return;
5358 }
5359 first = get_partition_start(pe);
5360 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5361 _("New beginning of data")) - pe->offset;
5362
5363 if (new != get_nr_sects(p)) {
5364 first = get_nr_sects(p) + get_start_sect(p) - new;
5365 set_nr_sects(p, first);
5366 set_start_sect(p, new);
5367 pe->changed = 1;
5368 }
5369}
5370
5371static void
5372xselect(void) {
5373 char c;
5374
5375 while(1) {
5376 putchar('\n');
5377 c = tolower(read_char(_("Expert command (m for help): ")));
5378 switch (c) {
5379 case 'a':
5380#ifdef CONFIG_FEATURE_SUN_LABEL
5381 if (sun_label)
5382 sun_set_alt_cyl();
5383#endif
5384 break;
5385 case 'b':
5386 if (dos_label)
5387 move_begin(get_partition(0, partitions));
5388 break;
5389 case 'c':
5390 user_cylinders = cylinders =
5391 read_int(1, cylinders, 1048576, 0,
5392 _("Number of cylinders"));
5393#ifdef CONFIG_FEATURE_SUN_LABEL
5394 if (sun_label)
5395 sun_set_ncyl(cylinders);
5396#endif
5397 if (dos_label)
5398 warn_cylinders();
5399 break;
5400 case 'd':
5401 print_raw();
5402 break;
5403 case 'e':
5404#ifdef CONFIG_FEATURE_SGI_LABEL
5405 if (sgi_label)
5406 sgi_set_xcyl();
5407 else
5408#endif
5409#ifdef CONFIG_FEATURE_SUN_LABEL
5410 if (sun_label)
5411 sun_set_xcyl();
5412 else
5413#endif
5414 if (dos_label)
5415 x_list_table(1);
5416 break;
5417 case 'f':
5418 if (dos_label)
5419 fix_partition_table_order();
5420 break;
5421 case 'g':
5422#ifdef CONFIG_FEATURE_SGI_LABEL
5423 create_sgilabel();
5424#endif
5425 break;
5426 case 'h':
5427 user_heads = heads = read_int(1, heads, 256, 0,
5428 _("Number of heads"));
5429 update_units();
5430 break;
5431 case 'i':
5432#ifdef CONFIG_FEATURE_SUN_LABEL
5433 if (sun_label)
5434 sun_set_ilfact();
5435#endif
5436 break;
5437 case 'o':
5438#ifdef CONFIG_FEATURE_SUN_LABEL
5439 if (sun_label)
5440 sun_set_rspeed();
5441#endif
5442 break;
5443 case 'p':
5444#ifdef CONFIG_FEATURE_SUN_LABEL
5445 if (sun_label)
5446 list_table(1);
5447 else
5448#endif
5449 x_list_table(0);
5450 break;
5451 case 'q':
5452 close(fd);
5453 printf("\n");
5454 exit(0);
5455 case 'r':
5456 return;
5457 case 's':
5458 user_sectors = sectors = read_int(1, sectors, 63, 0,
5459 _("Number of sectors"));
5460 if (dos_compatible_flag) {
5461 sector_offset = sectors;
5462 fprintf(stderr, _("Warning: setting "
5463 "sector offset for DOS "
5464 "compatiblity\n"));
5465 }
5466 update_units();
5467 break;
5468 case 'v':
5469 verify();
5470 break;
5471 case 'w':
5472 write_table(); /* does not return */
5473 break;
5474 case 'y':
5475#ifdef CONFIG_FEATURE_SUN_LABEL
5476 if (sun_label)
5477 sun_set_pcylcount();
5478#endif
5479 break;
5480 default:
5481 xmenu();
5482 }
5483 }
5484}
5485#endif /* ADVANCED mode */
5486
5487static int
5488is_ide_cdrom_or_tape(const char *device) {
5489 FILE *procf;
5490 char buf[100];
5491 struct stat statbuf;
5492 int is_ide = 0;
5493
5494 /* No device was given explicitly, and we are trying some
5495 likely things. But opening /dev/hdc may produce errors like
5496 "hdc: tray open or drive not ready"
5497 if it happens to be a CD-ROM drive. It even happens that
5498 the process hangs on the attempt to read a music CD.
5499 So try to be careful. This only works since 2.1.73. */
5500
5501 if (strncmp("/dev/hd", device, 7))
5502 return 0;
5503
5504 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5505 procf = fopen(buf, "r");
5506 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5507 is_ide = (!strncmp(buf, "cdrom", 5) ||
5508 !strncmp(buf, "tape", 4));
5509 else
5510 /* Now when this proc file does not exist, skip the
5511 device when it is read-only. */
5512 if (stat(device, &statbuf) == 0)
5513 is_ide = ((statbuf.st_mode & 0222) == 0);
5514
5515 if (procf)
5516 fclose(procf);
5517 return is_ide;
5518}
5519
5520static void
5521try(const char *device, int user_specified) {
5522 int gb;
5523
5524 disk_device = device;
5525 if (setjmp(listingbuf))
5526 return;
5527 if (!user_specified)
5528 if (is_ide_cdrom_or_tape(device))
5529 return;
5530 if ((fd = open(disk_device, type_open)) >= 0) {
5531 gb = get_boot(try_only);
5532 if (gb > 0) { /* I/O error */
5533 close(fd);
5534 } else if (gb < 0) { /* no DOS signature */
5535 list_disk_geometry();
5536 if (aix_label)
5537 return;
5538#ifdef CONFIG_FEATURE_OSF_LABEL
5539 if (btrydev(device) < 0)
5540#endif
5541 fprintf(stderr,
5542 _("Disk %s doesn't contain a valid "
5543 "partition table\n"), device);
5544 close(fd);
5545 } else {
5546 close(fd);
5547 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005548#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005549 if (!sun_label && partitions > 4)
5550 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005551#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005552 }
5553 } else {
5554 /* Ignore other errors, since we try IDE
5555 and SCSI hard disks which may not be
5556 installed on the system. */
5557 if (errno == EACCES) {
5558 fprintf(stderr, _("Cannot open %s\n"), device);
5559 return;
5560 }
5561 }
5562}
5563
5564/* for fdisk -l: try all things in /proc/partitions
5565 that look like a partition name (do not end in a digit) */
5566static void
5567tryprocpt(void) {
5568 FILE *procpt;
5569 char line[100], ptname[100], devname[120], *s;
5570 int ma, mi, sz;
5571
Manuel Novoa III cad53642003-03-19 09:13:01 +00005572 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005573
5574 while (fgets(line, sizeof(line), procpt)) {
5575 if (sscanf (line, " %d %d %d %[^\n ]",
5576 &ma, &mi, &sz, ptname) != 4)
5577 continue;
5578 for (s = ptname; *s; s++);
5579 if (isdigit(s[-1]))
5580 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005581 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005582 try(devname, 0);
5583 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005584#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005585 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005586#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005587}
5588
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005589#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005590static void
5591unknown_command(int c) {
5592 printf(_("%c: unknown command\n"), c);
5593}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005594#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005595
5596int fdisk_main(int argc, char **argv) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005597 int c;
5598#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5599 int optl = 0;
5600#endif
5601#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5602 int opts = 0;
5603#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005604 /*
5605 * Calls:
5606 * fdisk -v
5607 * fdisk -l [-b sectorsize] [-u] device ...
5608 * fdisk -s [partition] ...
5609 * fdisk [-b sectorsize] [-u] device
5610 *
5611 * Options -C, -H, -S set the geometry.
5612 *
5613 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005614 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5615#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5616 "s"
5617#endif
5618 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005619 switch (c) {
5620 case 'b':
5621 /* Ugly: this sector size is really per device,
5622 so cannot be combined with multiple disks,
5623 and te same goes for the C/H/S options.
5624 */
5625 sector_size = atoi(optarg);
5626 if (sector_size != 512 && sector_size != 1024 &&
5627 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005628 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005629 sector_offset = 2;
5630 user_set_sector_size = 1;
5631 break;
5632 case 'C':
5633 user_cylinders = atoi(optarg);
5634 break;
5635 case 'H':
5636 user_heads = atoi(optarg);
5637 if (user_heads <= 0 || user_heads >= 256)
5638 user_heads = 0;
5639 break;
5640 case 'S':
5641 user_sectors = atoi(optarg);
5642 if (user_sectors <= 0 || user_sectors >= 64)
5643 user_sectors = 0;
5644 break;
5645 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005646#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005647 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005648#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005649 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005650#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005651 case 's':
5652 opts = 1;
5653 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005654#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005655 case 'u':
5656 display_in_cyl_units = 0;
5657 break;
5658 case 'V':
5659 case 'v':
5660 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5661 return 0;
5662 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005663 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005664 }
5665 }
5666
5667#if 0
5668 printf(_("This kernel finds the sector size itself - "
5669 "-b option ignored\n"));
5670#else
5671 if (user_set_sector_size && argc-optind != 1)
5672 printf(_("Warning: the -b (set sector size) option should"
5673 " be used with one specified device\n"));
5674#endif
5675
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005676#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005677 if (optl) {
5678 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005679#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005680 type_open = O_RDONLY;
5681 if (argc > optind) {
5682 int k;
5683#if __GNUC__
5684 /* avoid gcc warning:
5685 variable `k' might be clobbered by `longjmp' */
5686 (void)&k;
5687#endif
5688 listing = 1;
5689 for (k=optind; k<argc; k++)
5690 try(argv[k], 1);
5691 } else {
5692 /* we no longer have default device names */
5693 /* but, we can use /proc/partitions instead */
5694 tryprocpt();
5695 }
5696 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005697#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005698 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005699#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005700
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005701#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005702 if (opts) {
5703 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005704 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005705
5706 nowarn = 1;
5707 type_open = O_RDONLY;
5708
5709 opts = argc - optind;
5710 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005711 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005712
5713 for (j = optind; j < argc; j++) {
5714 disk_device = argv[j];
5715 if ((fd = open(disk_device, type_open)) < 0)
5716 fdisk_fatal(unable_to_open);
5717 if (ioctl(fd, BLKGETSIZE, &size))
5718 fdisk_fatal(ioctl_error);
5719 close(fd);
5720 if (opts == 1)
5721 printf("%ld\n", size/2);
5722 else
5723 printf("%s: %ld\n", argv[j], size/2);
5724 }
5725 return 0;
5726 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005727#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005728
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005729#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005730 if (argc-optind == 1)
5731 disk_device = argv[optind];
5732 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005733 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005734
5735 get_boot(fdisk);
5736
5737#ifdef CONFIG_FEATURE_OSF_LABEL
5738 if (osf_label) {
5739 /* OSF label, and no DOS label */
5740 printf(_("Detected an OSF/1 disklabel on %s, entering "
5741 "disklabel mode.\n"),
5742 disk_device);
5743 bselect();
5744 osf_label = 0;
5745 /* If we return we may want to make an empty DOS label? */
5746 }
5747#endif
5748
5749 while (1) {
5750 putchar('\n');
5751 c = tolower(read_char(_("Command (m for help): ")));
5752 switch (c) {
5753 case 'a':
5754 if (dos_label)
5755 toggle_active(get_partition(1, partitions));
5756#ifdef CONFIG_FEATURE_SUN_LABEL
5757 else if (sun_label)
5758 toggle_sunflags(get_partition(1, partitions),
5759 0x01);
5760#endif
5761#ifdef CONFIG_FEATURE_SGI_LABEL
5762 else if (sgi_label)
5763 sgi_set_bootpartition(
5764 get_partition(1, partitions));
5765#endif
5766 else
5767 unknown_command(c);
5768 break;
5769 case 'b':
5770#ifdef CONFIG_FEATURE_SGI_LABEL
5771 if (sgi_label) {
5772 printf(_("\nThe current boot file is: %s\n"),
5773 sgi_get_bootfile());
5774 if (read_chars(_("Please enter the name of the "
5775 "new boot file: ")) == '\n')
5776 printf(_("Boot file unchanged\n"));
5777 else
5778 sgi_set_bootfile(line_ptr);
5779 } else
5780#endif
5781#ifdef CONFIG_FEATURE_OSF_LABEL
5782 bselect();
5783#endif
5784 break;
5785 case 'c':
5786 if (dos_label)
5787 toggle_dos_compatibility_flag();
5788#ifdef CONFIG_FEATURE_SUN_LABEL
5789 else if (sun_label)
5790 toggle_sunflags(get_partition(1, partitions),
5791 0x10);
5792#endif
5793#ifdef CONFIG_FEATURE_SGI_LABEL
5794 else if (sgi_label)
5795 sgi_set_swappartition(
5796 get_partition(1, partitions));
5797#endif
5798 else
5799 unknown_command(c);
5800 break;
5801 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005802 {
Eric Andersen040f4402003-07-30 08:40:37 +00005803 int j;
5804#ifdef CONFIG_FEATURE_SGI_LABEL
5805 /* If sgi_label then don't use get_existing_partition,
5806 let the user select a partition, since
5807 get_existing_partition() only works for Linux-like
5808 partition tables */
5809 if (!sgi_label) {
5810 j = get_existing_partition(1, partitions);
5811 } else {
5812 j = get_partition(1, partitions);
5813 }
5814#else
5815 j = get_existing_partition(1, partitions);
5816#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005817 if (j >= 0)
5818 delete_partition(j);
5819 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005820 break;
5821 case 'i':
5822#ifdef CONFIG_FEATURE_SGI_LABEL
5823 if (sgi_label)
5824 create_sgiinfo();
5825 else
5826#endif
5827 unknown_command(c);
5828 case 'l':
5829 list_types(get_sys_types());
5830 break;
5831 case 'm':
5832 menu();
5833 break;
5834 case 'n':
5835 new_partition();
5836 break;
5837 case 'o':
5838 create_doslabel();
5839 break;
5840 case 'p':
5841 list_table(0);
5842 break;
5843 case 'q':
5844 close(fd);
5845 printf("\n");
5846 return 0;
5847 case 's':
5848#ifdef CONFIG_FEATURE_SUN_LABEL
5849 create_sunlabel();
5850#endif
5851 break;
5852 case 't':
5853 change_sysid();
5854 break;
5855 case 'u':
5856 change_units();
5857 break;
5858 case 'v':
5859 verify();
5860 break;
5861 case 'w':
5862 write_table(); /* does not return */
5863 break;
5864#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5865 case 'x':
5866#ifdef CONFIG_FEATURE_SGI_LABEL
5867 if (sgi_label) {
5868 fprintf(stderr,
5869 _("\n\tSorry, no experts menu for SGI "
5870 "partition tables available.\n\n"));
5871 } else
5872#endif
5873
5874 xselect();
5875 break;
5876#endif
5877 default:
5878 unknown_command(c);
5879 menu();
5880 }
5881 }
5882 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005883#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005884}