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