blob: 02c5c10ff134ed435a0128a1038f94117976731d [file] [log] [blame]
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
4 *
5 * This program is free software. You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation: either version 1 or
8 * (at your option) any later version.
9 *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000010 * Vladimir Oleynik <dzo@simtreas.ru> 2001,2002 Busybox port
11 */
12
Eric Andersen99a75d12003-08-08 20:04:56 +000013#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014
15#define PROC_PARTITIONS "/proc/partitions"
16
17#include <sys/types.h>
18#include <sys/stat.h> /* stat */
19#include <ctype.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <setjmp.h>
27#include <assert.h> /* assert */
28#include <getopt.h>
29
30#include <endian.h>
31#define u_char unsigned char
32#include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */
33#undef u_char
34
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000035#include <sys/ioctl.h>
36#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000037#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000038
Eric Andersenacd244a2002-12-11 03:49:33 +000039#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
40
41/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000042#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000043
44#include <sys/utsname.h>
45
46#include "busybox.h"
47
48#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
49
50#define DKTYPENAMES
51
52#define _(Text) Text
53
54#define BLKRRPART _IO(0x12,95) /* re-read partition table */
55#define BLKGETSIZE _IO(0x12,96) /* return device size */
56#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
57#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersen040f4402003-07-30 08:40:37 +000058#define BLKGETSIZE64 _IOR(0x12,114,8) /* 8 = sizeof(u64) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000059
60/*
61 fdisk.h
62*/
63
64#define DEFAULT_SECTOR_SIZE 512
65#define MAX_SECTOR_SIZE 2048
66#define SECTOR_SIZE 512 /* still used in BSD code */
67#define MAXIMUM_PARTS 60
68
69#define ACTIVE_FLAG 0x80
70
71#define EXTENDED 0x05
72#define WIN98_EXTENDED 0x0f
73#define LINUX_PARTITION 0x81
74#define LINUX_SWAP 0x82
75#define LINUX_NATIVE 0x83
76#define LINUX_EXTENDED 0x85
77#define LINUX_LVM 0x8e
78#define LINUX_RAID 0xfd
79
80#define SUNOS_SWAP 3
81#define WHOLE_DISK 5
82
83#define IS_EXTENDED(i) \
84 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
85
86#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
87
88#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
89#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
90
Eric Andersend3652bf2003-08-06 09:07:37 +000091
92#if defined(CONFIG_LFS) || defined(FDISK_SUPPORT_LARGE_DISKS) || defined(__alpha__) || defined(__ia64__) || defined(__s390x__)
93typedef long long fdisk_loff_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000094#else
Eric Andersend3652bf2003-08-06 09:07:37 +000095typedef long fdisk_loff_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000096#endif
97
Eric Andersend3652bf2003-08-06 09:07:37 +000098
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000099/* including <linux/hdreg.h> also fails */
100struct hd_geometry {
101 unsigned char heads;
102 unsigned char sectors;
103 unsigned short cylinders;
104 unsigned long start;
105};
106
107#define HDIO_GETGEO 0x0301 /* get device geometry */
108
109
110struct systypes {
111 const unsigned char *name;
112};
113
Eric Andersen040f4402003-07-30 08:40:37 +0000114static uint sector_size = DEFAULT_SECTOR_SIZE,
115 user_set_sector_size,
116 sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000117
118/*
119 * Raw disk label. For DOS-type partition tables the MBR,
120 * with descriptions of the primary partitions.
121 */
122static char MBRbuffer[MAX_SECTOR_SIZE];
123
124#ifdef CONFIG_FEATURE_SUN_LABEL
125static int sun_label; /* looking at sun disklabel */
126#else
127#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000128#endif
129#ifdef CONFIG_FEATURE_SGI_LABEL
130static int sgi_label; /* looking at sgi disklabel */
131#else
132#define sgi_label 0
133#endif
134#ifdef CONFIG_FEATURE_AIX_LABEL
135static int aix_label; /* looking at aix disklabel */
136#else
137#define aix_label 0
138#endif
139#ifdef CONFIG_FEATURE_OSF_LABEL
140static int osf_label; /* looking at OSF/1 disklabel */
141static int possibly_osf_label;
142#else
143#define osf_label 0
144#endif
145
146#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
147
148static uint heads, sectors, cylinders;
149static void update_units(void);
150
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000151
152/*
153 * return partition name - uses static storage unless buf is supplied
154 */
155static const char *
156partname(const char *dev, int pno, int lth) {
157 static char buffer[80];
158 const char *p;
159 int w, wp;
160 int bufsiz;
161 char *bufp;
162
163 bufp = buffer;
164 bufsiz = sizeof(buffer);
165
166 w = strlen(dev);
167 p = "";
168
169 if (isdigit(dev[w-1]))
170 p = "p";
171
172 /* devfs kludge - note: fdisk partition names are not supposed
173 to equal kernel names, so there is no reason to do this */
174 if (strcmp (dev + w - 4, "disc") == 0) {
175 w -= 4;
176 p = "part";
177 }
178
179 wp = strlen(p);
180
181 if (lth) {
182 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
183 lth-wp-2, w, dev, p, pno);
184 } else {
185 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
186 }
187 return bufp;
188}
189
190struct partition {
191 unsigned char boot_ind; /* 0x80 - active */
192 unsigned char head; /* starting head */
193 unsigned char sector; /* starting sector */
194 unsigned char cyl; /* starting cylinder */
195 unsigned char sys_ind; /* What partition type */
196 unsigned char end_head; /* end head */
197 unsigned char end_sector; /* end sector */
198 unsigned char end_cyl; /* end cylinder */
199 unsigned char start4[4]; /* starting sector counting from 0 */
200 unsigned char size4[4]; /* nr of sectors in partition */
201};
202
203enum failure {
204 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
205 unable_to_write
206};
207
208enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
209
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000210static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000211static int fd; /* the disk */
212static int partitions = 4; /* maximum partition + 1 */
213static uint display_in_cyl_units = 1;
214static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000215#ifdef CONFIG_FEATURE_FDISK_WRITABLE
216static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000217static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000218static void reread_partition_table(int leave);
219static void delete_partition(int i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000220static int get_partition(int warn, int max);
221static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000222static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000223#endif
224static const char *partition_type(unsigned char type);
225static void fdisk_fatal(enum failure why) __attribute__ ((noreturn));
226static void get_geometry(void);
227static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000228
229#define PLURAL 0
230#define SINGULAR 1
231
232#define hex_val(c) ({ \
233 char _c = (c); \
234 isdigit(_c) ? _c - '0' : \
235 tolower(_c) + 10 - 'a'; \
236 })
237
238
239#define LINE_LENGTH 800
240#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
241 (n) * sizeof(struct partition)))
242#define sector(s) ((s) & 0x3f)
243#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
244
245#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
246 ((h) + heads * cylinder(s,c)))
247#define set_hsc(h,s,c,sector) { \
248 s = sector % sectors + 1; \
249 sector /= sectors; \
250 h = sector % heads; \
251 sector /= heads; \
252 c = sector & 0xff; \
253 s |= (sector >> 2) & 0xc0; \
254 }
255
256
257static unsigned int get_start_sect(const struct partition *p);
258static unsigned int get_nr_sects(const struct partition *p);
259
260/*
261 * per partition table entry data
262 *
263 * The four primary partitions have the same sectorbuffer (MBRbuffer)
264 * and have NULL ext_pointer.
265 * Each logical partition table entry has two pointers, one for the
266 * partition and one link to the next one.
267 */
268static struct pte {
269 struct partition *part_table; /* points into sectorbuffer */
270 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000271#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000272 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000273#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000274 uint offset; /* disk sector number */
275 char *sectorbuffer; /* disk sector contents */
276} ptes[MAXIMUM_PARTS];
277
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000278
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000279#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000280static void
281set_all_unchanged(void) {
282 int i;
283
284 for (i = 0; i < MAXIMUM_PARTS; i++)
285 ptes[i].changed = 0;
286}
287
288static void
289set_changed(int i) {
290 ptes[i].changed = 1;
291}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000292#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000293
294#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
295static struct partition *
296get_part_table(int i) {
297 return ptes[i].part_table;
298}
299#endif
300
301static const char *
302str_units(int n) { /* n==1: use singular */
303 if (n == 1)
304 return display_in_cyl_units ? _("cylinder") : _("sector");
305 else
306 return display_in_cyl_units ? _("cylinders") : _("sectors");
307}
308
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000309static int
310valid_part_table_flag(const unsigned char *b) {
311 return (b[510] == 0x55 && b[511] == 0xaa);
312}
313
314#ifdef CONFIG_FEATURE_FDISK_WRITABLE
315static char line_buffer[LINE_LENGTH];
316
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000317/* read line; return 0 or first char */
318static int
319read_line(void)
320{
321 static int got_eof = 0;
322
323 fflush (stdout); /* requested by niles@scyld.com */
324 line_ptr = line_buffer;
325 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
326 if (feof(stdin))
327 got_eof++; /* user typed ^D ? */
328 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000329 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
330 exit(1);
331 }
332 return 0;
333 }
334 while (*line_ptr && !isgraph(*line_ptr))
335 line_ptr++;
336 return *line_ptr;
337}
338
339static char
340read_char(const char *mesg)
341{
342 do {
343 fputs(mesg, stdout);
344 } while (!read_line());
345 return *line_ptr;
346}
347
348static char
349read_chars(const char *mesg)
350{
351 fputs(mesg, stdout);
352 if (!read_line()) {
353 *line_ptr = '\n';
354 line_ptr[1] = 0;
355 }
356 return *line_ptr;
357}
358
359static int
360read_hex(const struct systypes *sys)
361{
362 int hex;
363
364 while (1)
365 {
366 read_char(_("Hex code (type L to list codes): "));
367 if (*line_ptr == 'l' || *line_ptr == 'L')
368 list_types(sys);
369 else if (isxdigit (*line_ptr))
370 {
371 hex = 0;
372 do
373 hex = hex << 4 | hex_val(*line_ptr++);
374 while (isxdigit(*line_ptr));
375 return hex;
376 }
377 }
378}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000379#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000380
381#ifdef CONFIG_FEATURE_AIX_LABEL
382/*
383 * Copyright (C) Andreas Neuper, Sep 1998.
384 * This file may be redistributed under
385 * the terms of the GNU Public License.
386 */
387
388typedef struct {
389 unsigned int magic; /* expect AIX_LABEL_MAGIC */
390 unsigned int fillbytes1[124];
391 unsigned int physical_volume_id;
392 unsigned int fillbytes2[124];
393} aix_partition;
394
395#define AIX_LABEL_MAGIC 0xc9c2d4c1
396#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
397#define AIX_INFO_MAGIC 0x00072959
398#define AIX_INFO_MAGIC_SWAPPED 0x59290700
399
400#define aixlabel ((aix_partition *)MBRbuffer)
401
402
403/*
404 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000405 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
406 * Internationalization
407 *
408 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
409 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000410*/
411
412static int aix_other_endian;
413static short aix_volumes=1;
414
415/*
416 * only dealing with free blocks here
417 */
418
419static void
420aix_info( void ) {
421 puts(
422 _("\n\tThere is a valid AIX label on this disk.\n"
423 "\tUnfortunately Linux cannot handle these\n"
424 "\tdisks at the moment. Nevertheless some\n"
425 "\tadvice:\n"
426 "\t1. fdisk will destroy its contents on write.\n"
427 "\t2. Be sure that this disk is NOT a still vital\n"
428 "\t part of a volume group. (Otherwise you may\n"
429 "\t erase the other disks as well, if unmirrored.)\n"
430 "\t3. Before deleting this physical volume be sure\n"
431 "\t to remove the disk logically from your AIX\n"
432 "\t machine. (Otherwise you become an AIXpert).")
433 );
434}
435
436static void
437aix_nolabel( void )
438{
439 aixlabel->magic = 0;
440 aix_label = 0;
441 partitions = 4;
442 memset( MBRbuffer, 0, sizeof(MBRbuffer) ); /* avoid fdisk cores */
443 return;
444}
445
446static int
447check_aix_label( void )
448{
449 if (aixlabel->magic != AIX_LABEL_MAGIC &&
450 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
451 aix_label = 0;
452 aix_other_endian = 0;
453 return 0;
454 }
455 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
456 update_units();
457 aix_label = 1;
458 partitions= 1016;
459 aix_volumes = 15;
460 aix_info();
461 aix_nolabel(); /* %% */
462 aix_label = 1; /* %% */
463 return 1;
464}
465#endif /* AIX_LABEL */
466
467#ifdef CONFIG_FEATURE_OSF_LABEL
468/*
469 * Copyright (c) 1987, 1988 Regents of the University of California.
470 * All rights reserved.
471 *
472 * Redistribution and use in source and binary forms, with or without
473 * modification, are permitted provided that the following conditions
474 * are met:
475 * 1. Redistributions of source code must retain the above copyright
476 * notice, this list of conditions and the following disclaimer.
477 * 2. Redistributions in binary form must reproduce the above copyright
478 * notice, this list of conditions and the following disclaimer in the
479 * documentation and/or other materials provided with the distribution.
480 * 3. All advertising materials mentioning features or use of this software
481 * must display the following acknowledgement:
482 * This product includes software developed by the University of
483 * California, Berkeley and its contributors.
484 * 4. Neither the name of the University nor the names of its contributors
485 * may be used to endorse or promote products derived from this software
486 * without specific prior written permission.
487 *
488 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
489 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
490 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
491 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
492 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
493 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
494 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
495 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
496 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
497 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
498 * SUCH DAMAGE.
499 */
500
501
502#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000503#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000504#endif
505
506#ifndef BSD_MAXPARTITIONS
507#define BSD_MAXPARTITIONS 16
508#endif
509
510#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
511
512#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
513#define BSD_LABELSECTOR 1
514#define BSD_LABELOFFSET 0
515#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
516#define BSD_LABELSECTOR 0
517#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000518#elif defined (__s390__) || defined (__s390x__)
519#define BSD_LABELSECTOR 1
520#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000521#else
522#error unknown architecture
523#endif
524
525#define BSD_BBSIZE 8192 /* size of boot area, with label */
526#define BSD_SBSIZE 8192 /* max size of fs superblock */
527
528struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000529 uint32_t d_magic; /* the magic number */
530 int16_t d_type; /* drive type */
531 int16_t d_subtype; /* controller/d_type specific */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000532 char d_typename[16]; /* type name, e.g. "eagle" */
533 char d_packname[16]; /* pack identifier */
534 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000535 uint32_t d_secsize; /* # of bytes per sector */
536 uint32_t d_nsectors; /* # of data sectors per track */
537 uint32_t d_ntracks; /* # of tracks per cylinder */
538 uint32_t d_ncylinders; /* # of data cylinders per unit */
539 uint32_t d_secpercyl; /* # of data sectors per cylinder */
540 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000541 /*
542 * Spares (bad sector replacements) below
543 * are not counted in d_nsectors or d_secpercyl.
544 * Spare sectors are assumed to be physical sectors
545 * which occupy space at the end of each track and/or cylinder.
546 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000547 uint16_t d_sparespertrack; /* # of spare sectors per track */
548 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000549 /*
550 * Alternate cylinders include maintenance, replacement,
551 * configuration description areas, etc.
552 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000553 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000554
555 /* hardware characteristics: */
556 /*
557 * d_interleave, d_trackskew and d_cylskew describe perturbations
558 * in the media format used to compensate for a slow controller.
559 * Interleave is physical sector interleave, set up by the formatter
560 * or controller when formatting. When interleaving is in use,
561 * logically adjacent sectors are not physically contiguous,
562 * but instead are separated by some number of sectors.
563 * It is specified as the ratio of physical sectors traversed
564 * per logical sector. Thus an interleave of 1:1 implies contiguous
565 * layout, while 2:1 implies that logical sector 0 is separated
566 * by one sector from logical sector 1.
567 * d_trackskew is the offset of sector 0 on track N
568 * relative to sector 0 on track N-1 on the same cylinder.
569 * Finally, d_cylskew is the offset of sector 0 on cylinder N
570 * relative to sector 0 on cylinder N-1.
571 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000572 uint16_t d_rpm; /* rotational speed */
573 uint16_t d_interleave; /* hardware sector interleave */
574 uint16_t d_trackskew; /* sector 0 skew, per track */
575 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
576 uint32_t d_headswitch; /* head switch time, usec */
577 uint32_t d_trkseek; /* track-to-track seek, usec */
578 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000579#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000580 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000581#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000582 uint32_t d_spare[NSPARE]; /* reserved for future use */
583 uint32_t d_magic2; /* the magic number (again) */
584 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000585 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000586 uint16_t d_npartitions; /* number of partitions in following */
587 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
588 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000589 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000590 uint32_t p_size; /* number of sectors in partition */
591 uint32_t p_offset; /* starting sector */
592 uint32_t p_fsize; /* filesystem basic fragment size */
593 uint8_t p_fstype; /* filesystem type, see below */
594 uint8_t p_frag; /* filesystem fragments per block */
595 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000596 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
597};
598
599/* d_type values: */
600#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
601#define BSD_DTYPE_MSCP 2 /* MSCP */
602#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
603#define BSD_DTYPE_SCSI 4 /* SCSI */
604#define BSD_DTYPE_ESDI 5 /* ESDI interface */
605#define BSD_DTYPE_ST506 6 /* ST506 etc. */
606#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
607#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
608#define BSD_DTYPE_FLOPPY 10 /* floppy */
609
610/* d_subtype values: */
611#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
612#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
613#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
614
615#ifdef DKTYPENAMES
616static const char * const xbsd_dktypenames[] = {
617 "unknown",
618 "SMD",
619 "MSCP",
620 "old DEC",
621 "SCSI",
622 "ESDI",
623 "ST506",
624 "HP-IB",
625 "HP-FL",
626 "type 9",
627 "floppy",
628 0
629};
630#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
631#endif
632
633/*
634 * Filesystem type and version.
635 * Used to interpret other filesystem-specific
636 * per-partition information.
637 */
638#define BSD_FS_UNUSED 0 /* unused */
639#define BSD_FS_SWAP 1 /* swap */
640#define BSD_FS_V6 2 /* Sixth Edition */
641#define BSD_FS_V7 3 /* Seventh Edition */
642#define BSD_FS_SYSV 4 /* System V */
643#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
644#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
645#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
646#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
647#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
648#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
649#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
650#define BSD_FS_ISOFS BSD_FS_ISO9660
651#define BSD_FS_BOOT 13 /* partition contains bootstrap */
652#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
653#define BSD_FS_HFS 15 /* Macintosh HFS */
654#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
655
656/* this is annoying, but it's also the way it is :-( */
657#ifdef __alpha__
658#define BSD_FS_EXT2 8 /* ext2 file system */
659#else
660#define BSD_FS_MSDOS 8 /* MS-DOS file system */
661#endif
662
663#ifdef DKTYPENAMES
664static const struct systypes xbsd_fstypes[] = {
665/* BSD_FS_UNUSED */ {"\x00" "unused"},
666/* BSD_FS_SWAP */ {"\x01" "swap"},
667/* BSD_FS_V6 */ {"\x02" "Version 6"},
668/* BSD_FS_V7 */ {"\x03" "Version 7"},
669/* BSD_FS_SYSV */ {"\x04" "System V"},
670/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
671/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
672/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
673#ifdef __alpha__
674/* BSD_FS_EXT2 */ {"\x08" "ext2"},
675#else
676/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
677#endif
678/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
679/* BSD_FS_OTHER */ {"\x0a" "unknown"},
680/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
681/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
682/* BSD_FS_BOOT */ {"\x0d" "boot"},
683/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
684/* BSD_FS_HFS */ {"\x0f" "HFS"},
685/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
686 { NULL }
687};
688#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
689
690#endif
691
692/*
693 * flags shared by various drives:
694 */
695#define BSD_D_REMOVABLE 0x01 /* removable media */
696#define BSD_D_ECC 0x02 /* supports ECC */
697#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
698#define BSD_D_RAMDISK 0x08 /* disk emulator */
699#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
700#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
701
702#endif /* OSF_LABEL */
703
704/*
705 * Copyright (C) Andreas Neuper, Sep 1998.
706 * This file may be modified and redistributed under
707 * the terms of the GNU Public License.
708 */
709
710struct device_parameter { /* 48 bytes */
711 unsigned char skew;
712 unsigned char gap1;
713 unsigned char gap2;
714 unsigned char sparecyl;
715 unsigned short pcylcount;
716 unsigned short head_vol0;
717 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
718 unsigned char cmd_tag_queue_depth;
719 unsigned char unused0;
720 unsigned short unused1;
721 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
722 unsigned short bytes;
723 unsigned short ilfact;
724 unsigned int flags; /* controller flags */
725 unsigned int datarate;
726 unsigned int retries_on_error;
727 unsigned int ms_per_word;
728 unsigned short xylogics_gap1;
729 unsigned short xylogics_syncdelay;
730 unsigned short xylogics_readdelay;
731 unsigned short xylogics_gap2;
732 unsigned short xylogics_readgate;
733 unsigned short xylogics_writecont;
734};
735
736#define SGI_VOLHDR 0x00
737/* 1 and 2 were used for drive types no longer supported by SGI */
738#define SGI_SWAP 0x03
739/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
740#define SGI_VOLUME 0x06
741#define SGI_EFS 0x07
742#define SGI_LVOL 0x08
743#define SGI_RLVOL 0x09
744#define SGI_XFS 0x0a
745#define SGI_XFSLOG 0x0b
746#define SGI_XLV 0x0c
747#define SGI_XVM 0x0d
748#define ENTIRE_DISK SGI_VOLUME
749/*
750 * controller flags
751 */
752#define SECTOR_SLIP 0x01
753#define SECTOR_FWD 0x02
754#define TRACK_FWD 0x04
755#define TRACK_MULTIVOL 0x08
756#define IGNORE_ERRORS 0x10
757#define RESEEK 0x20
758#define ENABLE_CMDTAGQ 0x40
759
760typedef struct {
761 unsigned int magic; /* expect SGI_LABEL_MAGIC */
762 unsigned short boot_part; /* active boot partition */
763 unsigned short swap_part; /* active swap partition */
764 unsigned char boot_file[16]; /* name of the bootfile */
765 struct device_parameter devparam; /* 1 * 48 bytes */
766 struct volume_directory { /* 15 * 16 bytes */
767 unsigned char vol_file_name[8]; /* a character array */
768 unsigned int vol_file_start; /* number of logical block */
769 unsigned int vol_file_size; /* number of bytes */
770 } directory[15];
771 struct sgi_partition { /* 16 * 12 bytes */
772 unsigned int num_sectors; /* number of blocks */
773 unsigned int start_sector; /* must be cylinder aligned */
774 unsigned int id;
775 } partitions[16];
776 unsigned int csum;
777 unsigned int fillbytes;
778} sgi_partition;
779
780typedef struct {
781 unsigned int magic; /* looks like a magic number */
782 unsigned int a2;
783 unsigned int a3;
784 unsigned int a4;
785 unsigned int b1;
786 unsigned short b2;
787 unsigned short b3;
788 unsigned int c[16];
789 unsigned short d[3];
790 unsigned char scsi_string[50];
791 unsigned char serial[137];
792 unsigned short check1816;
793 unsigned char installer[225];
794} sgiinfo;
795
796#define SGI_LABEL_MAGIC 0x0be5a941
797#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
798#define SGI_INFO_MAGIC 0x00072959
799#define SGI_INFO_MAGIC_SWAPPED 0x59290700
800#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000801 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000802#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000803 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000804
805#define sgilabel ((sgi_partition *)MBRbuffer)
806#define sgiparam (sgilabel->devparam)
807
808typedef struct {
809 unsigned char info[128]; /* Informative text string */
810 unsigned char spare0[14];
811 struct sun_info {
812 unsigned char spare1;
813 unsigned char id;
814 unsigned char spare2;
815 unsigned char flags;
816 } infos[8];
817 unsigned char spare1[246]; /* Boot information etc. */
818 unsigned short rspeed; /* Disk rotational speed */
819 unsigned short pcylcount; /* Physical cylinder count */
820 unsigned short sparecyl; /* extra sects per cylinder */
821 unsigned char spare2[4]; /* More magic... */
822 unsigned short ilfact; /* Interleave factor */
823 unsigned short ncyl; /* Data cylinder count */
824 unsigned short nacyl; /* Alt. cylinder count */
825 unsigned short ntrks; /* Tracks per cylinder */
826 unsigned short nsect; /* Sectors per track */
827 unsigned char spare3[4]; /* Even more magic... */
828 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000829 uint32_t start_cylinder;
830 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000831 } partitions[8];
832 unsigned short magic; /* Magic number */
833 unsigned short csum; /* Label xor'd checksum */
834} sun_partition;
835
Eric Andersen040f4402003-07-30 08:40:37 +0000836
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000837#define SUN_LABEL_MAGIC 0xDABE
838#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
839#define sunlabel ((sun_partition *)MBRbuffer)
840#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000841 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000842#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000843 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000844
Eric Andersend3652bf2003-08-06 09:07:37 +0000845#if defined(FDISK_SUPPORT_LARGE_DISKS)
846/*
847 * llseek.c -- stub calling the llseek system call
848 *
849 * Copyright (C) 1994 Remy Card. This file may be redistributed
850 * under the terms of the GNU Public License.
851 */
852
853
854#include <syscall.h>
855
856
857#if defined(__alpha__) || defined(__ia64__) || defined(__s390x__)
858
859#define my_llseek lseek
860
861#else
862
863static int _llseek (unsigned int, unsigned long,
864 unsigned long, fdisk_loff_t *, unsigned int);
865
866static _syscall5(int,_llseek,unsigned int,f_d,unsigned long,offset_high,
867 unsigned long, offset_low,fdisk_loff_t *,result,
868 unsigned int, origin)
869
870static fdisk_loff_t my_llseek (unsigned int f_d, fdisk_loff_t offset,
871 unsigned int origin)
872{
873 fdisk_loff_t result;
874 int retval;
875
876 retval = _llseek (f_d, ((unsigned long long) offset) >> 32,
877 ((unsigned long long) offset) & 0xffffffff,
878 &result, origin);
879 return (retval == -1 ? (fdisk_loff_t) retval : result);
880}
881
882#endif /* __alpha__ */
883
884
885static fdisk_loff_t fdisk_llseek (unsigned int f_d, fdisk_loff_t offset,
886 unsigned int origin)
887{
888 fdisk_loff_t result;
889 static int do_compat = 0;
890
891 if (!do_compat) {
892 result = my_llseek (f_d, offset, origin);
893 if (!(result == -1 && errno == ENOSYS))
894 return result;
895
896 /*
897 * Just in case this code runs on top of an old kernel
898 * which does not support the llseek system call
899 */
900 do_compat = 1;
901 /*
902 * Now try ordinary lseek.
903 */
904 }
905
906 if ((sizeof(off_t) >= sizeof(fdisk_loff_t)) ||
907 (offset < ((fdisk_loff_t) 1 << ((sizeof(off_t)*8) -1))))
908 return lseek(f_d, (off_t) offset, origin);
909
910 errno = EINVAL;
911 return -1;
912}
913#else
914# define fdisk_llseek lseek
915#endif /* FDISK_SUPPORT_LARGE_DISKS */
916
917
918
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000919#ifdef CONFIG_FEATURE_OSF_LABEL
920/*
921 Changes:
922 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
923
924 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
925 support for OSF/1 disklabels on Alpha.
926 Also fixed unaligned accesses in alpha_bootblock_checksum()
927*/
928
929#define FREEBSD_PARTITION 0xa5
930#define NETBSD_PARTITION 0xa9
931
932static void xbsd_delete_part (void);
933static void xbsd_new_part (void);
934static void xbsd_write_disklabel (void);
935static int xbsd_create_disklabel (void);
936static void xbsd_edit_disklabel (void);
937static void xbsd_write_bootstrap (void);
938static void xbsd_change_fstype (void);
939static int xbsd_get_part_index (int max);
940static int xbsd_check_new_partition (int *i);
941static void xbsd_list_types (void);
942static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
943static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d,
944 int pindex);
945static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
946static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
947
948#if defined (__alpha__)
949static void alpha_bootblock_checksum (char *boot);
950#endif
951
952#if !defined (__alpha__)
953static int xbsd_translate_fstype (int linux_type);
954static void xbsd_link_part (void);
955static struct partition *xbsd_part;
956static int xbsd_part_index;
957#endif
958
959#if defined (__alpha__)
960/* We access this through a u_int64_t * when checksumming */
961static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
962#else
963static char disklabelbuffer[BSD_BBSIZE];
964#endif
965
966static struct xbsd_disklabel xbsd_dlabel;
967
968#define bsd_cround(n) \
969 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
970
971/*
972 * Test whether the whole disk has BSD disk label magic.
973 *
974 * Note: often reformatting with DOS-type label leaves the BSD magic,
975 * so this does not mean that there is a BSD disk label.
976 */
977static int
978check_osf_label(void) {
979 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
980 return 0;
981 return 1;
982}
983
984static void xbsd_print_disklabel(int);
985
986static int
Glenn L McGrath35631a62002-12-08 11:51:05 +0000987btrydev (const char * dev) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000988 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
989 return -1;
990 printf(_("\nBSD label for device: %s\n"), dev);
991 xbsd_print_disklabel (0);
992 return 0;
993}
994
995static void
996bmenu (void) {
997 puts (_("Command action"));
998 puts (_("\td\tdelete a BSD partition"));
999 puts (_("\te\tedit drive data"));
1000 puts (_("\ti\tinstall bootstrap"));
1001 puts (_("\tl\tlist known filesystem types"));
1002 puts (_("\tm\tprint this menu"));
1003 puts (_("\tn\tadd a new BSD partition"));
1004 puts (_("\tp\tprint BSD partition table"));
1005 puts (_("\tq\tquit without saving changes"));
1006 puts (_("\tr\treturn to main menu"));
1007 puts (_("\ts\tshow complete disklabel"));
1008 puts (_("\tt\tchange a partition's filesystem id"));
1009 puts (_("\tu\tchange units (cylinders/sectors)"));
1010 puts (_("\tw\twrite disklabel to disk"));
1011#if !defined (__alpha__)
1012 puts (_("\tx\tlink BSD partition to non-BSD partition"));
1013#endif
1014}
1015
1016#if !defined (__alpha__)
1017static int
1018hidden(int type) {
1019 return type ^ 0x10;
1020}
1021
1022static int
1023is_bsd_partition_type(int type) {
1024 return (type == FREEBSD_PARTITION ||
1025 type == hidden(FREEBSD_PARTITION) ||
1026 type == NETBSD_PARTITION ||
1027 type == hidden(NETBSD_PARTITION));
1028}
1029#endif
1030
1031static void
1032bselect (void) {
1033#if !defined (__alpha__)
1034 int t, ss;
1035 struct partition *p;
1036
1037 for (t=0; t<4; t++) {
1038 p = get_part_table(t);
1039 if (p && is_bsd_partition_type(p->sys_ind)) {
1040 xbsd_part = p;
1041 xbsd_part_index = t;
1042 ss = get_start_sect(xbsd_part);
1043 if (ss == 0) {
1044 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
1045 partname(disk_device, t+1, 0));
1046 return;
1047 }
1048 printf (_("Reading disklabel of %s at sector %d.\n"),
1049 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
1050 if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
1051 if (xbsd_create_disklabel () == 0)
1052 return;
1053 break;
1054 }
1055 }
1056
1057 if (t == 4) {
1058 printf (_("There is no *BSD partition on %s.\n"), disk_device);
1059 return;
1060 }
1061
1062#elif defined (__alpha__)
1063
1064 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
1065 if (xbsd_create_disklabel () == 0)
1066 exit ( EXIT_SUCCESS );
1067
1068#endif
1069
1070 while (1) {
1071 putchar ('\n');
1072 switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
1073 case 'd':
1074 xbsd_delete_part ();
1075 break;
1076 case 'e':
1077 xbsd_edit_disklabel ();
1078 break;
1079 case 'i':
1080 xbsd_write_bootstrap ();
1081 break;
1082 case 'l':
1083 xbsd_list_types ();
1084 break;
1085 case 'n':
1086 xbsd_new_part ();
1087 break;
1088 case 'p':
1089 xbsd_print_disklabel (0);
1090 break;
1091 case 'q':
1092 close (fd);
1093 exit ( EXIT_SUCCESS );
1094 case 'r':
1095 return;
1096 case 's':
1097 xbsd_print_disklabel (1);
1098 break;
1099 case 't':
1100 xbsd_change_fstype ();
1101 break;
1102 case 'u':
1103 change_units();
1104 break;
1105 case 'w':
1106 xbsd_write_disklabel ();
1107 break;
1108#if !defined (__alpha__)
1109 case 'x':
1110 xbsd_link_part ();
1111 break;
1112#endif
1113 default:
1114 bmenu ();
1115 break;
1116 }
1117 }
1118}
1119
1120static void
1121xbsd_delete_part (void)
1122{
1123 int i;
1124
1125 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1126 xbsd_dlabel.d_partitions[i].p_size = 0;
1127 xbsd_dlabel.d_partitions[i].p_offset = 0;
1128 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1129 if (xbsd_dlabel.d_npartitions == i + 1)
1130 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1131 xbsd_dlabel.d_npartitions--;
1132}
1133
1134static void
1135xbsd_new_part (void)
1136{
1137 uint begin, end;
1138 char mesg[256];
1139 int i;
1140
1141 if (!xbsd_check_new_partition (&i))
1142 return;
1143
1144#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1145 begin = get_start_sect(xbsd_part);
1146 end = begin + get_nr_sects(xbsd_part) - 1;
1147#else
1148 begin = 0;
1149 end = xbsd_dlabel.d_secperunit - 1;
1150#endif
1151
1152 snprintf (mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1153 begin = read_int (bsd_cround (begin), bsd_cround (begin), bsd_cround (end),
1154 0, mesg);
1155
1156 if (display_in_cyl_units)
1157 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
1158
1159 snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1160 str_units(SINGULAR));
1161 end = read_int (bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1162 bsd_cround (begin), mesg);
1163
1164 if (display_in_cyl_units)
1165 end = end * xbsd_dlabel.d_secpercyl - 1;
1166
1167 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1168 xbsd_dlabel.d_partitions[i].p_offset = begin;
1169 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1170}
1171
1172static void
1173xbsd_print_disklabel (int show_all) {
1174 struct xbsd_disklabel *lp = &xbsd_dlabel;
1175 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001176 int i, j;
1177
1178 if (show_all) {
1179#if defined (__alpha__)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001180 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001181#else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001182 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001183#endif
1184 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001185 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001186 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001187 printf(_("type: %d\n"), lp->d_type);
1188 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1189 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1190 printf(_("flags:"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001191 if (lp->d_flags & BSD_D_REMOVABLE)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001192 printf(_(" removable"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001193 if (lp->d_flags & BSD_D_ECC)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001194 printf(_(" ecc"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001195 if (lp->d_flags & BSD_D_BADSECT)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001196 printf(_(" badsect"));
1197 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001198 /* On various machines the fields of *lp are short/int/long */
1199 /* In order to avoid problems, we cast them all to long. */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001200 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1201 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1202 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1203 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1204 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1205 printf(_("rpm: %d\n"), lp->d_rpm);
1206 printf(_("interleave: %d\n"), lp->d_interleave);
1207 printf(_("trackskew: %d\n"), lp->d_trackskew);
1208 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1209 printf(_("headswitch: %ld\t\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001210 (long) lp->d_headswitch);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001211 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001212 (long) lp->d_trkseek);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001213 printf(_("drivedata: "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001214 for (i = NDDATA - 1; i >= 0; i--)
1215 if (lp->d_drivedata[i])
1216 break;
1217 if (i < 0)
1218 i = 0;
1219 for (j = 0; j <= i; j++)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001220 printf("%ld ", (long) lp->d_drivedata[j]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001221 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001222 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1223 printf(_("# start end size fstype [fsize bsize cpg]\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001224 pp = lp->d_partitions;
1225 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1226 if (pp->p_size) {
1227 if (display_in_cyl_units && lp->d_secpercyl) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001228 printf(" %c: %8ld%c %8ld%c %8ld%c ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001229 'a' + i,
1230 (long) pp->p_offset / lp->d_secpercyl + 1,
1231 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1232 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
1233 / lp->d_secpercyl,
1234 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1235 (long) pp->p_size / lp->d_secpercyl,
1236 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
1237 } else {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001238 printf(" %c: %8ld %8ld %8ld ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001239 'a' + i,
1240 (long) pp->p_offset,
1241 (long) pp->p_offset + pp->p_size - 1,
1242 (long) pp->p_size);
1243 }
1244 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001245 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001246 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001247 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001248 switch (pp->p_fstype) {
1249 case BSD_FS_UNUSED:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001250 printf(" %5ld %5ld %5.5s ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001251 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1252 break;
1253
1254 case BSD_FS_BSDFFS:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001255 printf(" %5ld %5ld %5d ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001256 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
1257 pp->p_cpg);
1258 break;
1259
1260 default:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001261 printf("%22.22s", "");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001262 break;
1263 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001264 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001265 }
1266 }
1267}
1268
1269static void
1270xbsd_write_disklabel (void) {
1271#if defined (__alpha__)
1272 printf (_("Writing disklabel to %s.\n"), disk_device);
1273 xbsd_writelabel (NULL, &xbsd_dlabel);
1274#else
1275 printf (_("Writing disklabel to %s.\n"),
1276 partname(disk_device, xbsd_part_index+1, 0));
1277 xbsd_writelabel (xbsd_part, &xbsd_dlabel);
1278#endif
1279 reread_partition_table(0); /* no exit yet */
1280}
1281
1282static int
1283xbsd_create_disklabel (void) {
1284 char c;
1285
1286#if defined (__alpha__)
1287 fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
1288#else
1289 fprintf (stderr, _("%s contains no disklabel.\n"),
1290 partname(disk_device, xbsd_part_index+1, 0));
1291#endif
1292
1293 while (1) {
1294 c = read_char (_("Do you want to create a disklabel? (y/n) "));
1295 if (c == 'y' || c == 'Y') {
1296 if (xbsd_initlabel (
Eric Andersen040f4402003-07-30 08:40:37 +00001297#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
1298 defined (__s390__) || defined (__s390x__)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001299 NULL, &xbsd_dlabel, 0
1300#else
1301 xbsd_part, &xbsd_dlabel, xbsd_part_index
1302#endif
1303 ) == 1) {
1304 xbsd_print_disklabel (1);
1305 return 1;
1306 } else
1307 return 0;
1308 } else if (c == 'n')
1309 return 0;
1310 }
1311}
1312
1313static int
1314edit_int (int def, char *mesg)
1315{
1316 do {
1317 fputs (mesg, stdout);
1318 printf (" (%d): ", def);
1319 if (!read_line ())
1320 return def;
1321 }
1322 while (!isdigit (*line_ptr));
1323 return atoi (line_ptr);
1324}
1325
1326static void
1327xbsd_edit_disklabel (void)
1328{
1329 struct xbsd_disklabel *d;
1330
1331 d = &xbsd_dlabel;
1332
1333#if defined (__alpha__) || defined (__ia64__)
1334 d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,_("bytes/sector"));
1335 d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,_("sectors/track"));
1336 d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,_("tracks/cylinder"));
1337 d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,_("cylinders"));
1338#endif
1339
1340 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
1341 while (1)
1342 {
1343 d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
1344 _("sectors/cylinder"));
1345 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
1346 break;
1347
1348 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1349 }
1350 d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,_("rpm"));
1351 d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
1352 d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
1353 d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,_("cylinderskew"));
1354 d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,_("headswitch"));
1355 d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,_("track-to-track seek"));
1356
1357 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1358}
1359
1360static int
1361xbsd_get_bootstrap (char *path, void *ptr, int size)
1362{
1363 int fdb;
1364
1365 if ((fdb = open (path, O_RDONLY)) < 0)
1366 {
1367 perror (path);
1368 return 0;
1369 }
1370 if (read (fdb, ptr, size) < 0)
1371 {
1372 perror (path);
1373 close (fdb);
1374 return 0;
1375 }
1376 printf (" ... %s\n", path);
1377 close (fdb);
1378 return 1;
1379}
1380
1381static void
1382sync_disks (void)
1383{
1384 printf (_("\nSyncing disks.\n"));
1385 sync ();
1386 sleep (4);
1387}
1388
1389static void
1390xbsd_write_bootstrap (void)
1391{
1392 char *bootdir = BSD_LINUX_BOOTDIR;
1393 char path[MAXPATHLEN];
1394 char *dkbasename;
1395 struct xbsd_disklabel dl;
1396 char *d, *p, *e;
1397 int sector;
1398
1399 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1400 dkbasename = "sd";
1401 else
1402 dkbasename = "wd";
1403
1404 printf (_("Bootstrap: %sboot -> boot%s (%s): "),
1405 dkbasename, dkbasename, dkbasename);
1406 if (read_line ()) {
1407 line_ptr[strlen (line_ptr)-1] = '\0';
1408 dkbasename = line_ptr;
1409 }
1410 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1411 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1412 return;
1413
1414 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1415 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1416 bcopy (d, &dl, sizeof (struct xbsd_disklabel));
1417
1418 /* The disklabel will be overwritten by 0's from bootxx anyway */
1419 bzero (d, sizeof (struct xbsd_disklabel));
1420
1421 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1422 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1423 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1424 return;
1425
1426 e = d + sizeof (struct xbsd_disklabel);
1427 for (p=d; p < e; p++)
1428 if (*p) {
1429 fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
1430 exit ( EXIT_FAILURE );
1431 }
1432
1433 bcopy (&dl, d, sizeof (struct xbsd_disklabel));
1434
1435#if defined (__powerpc__) || defined (__hppa__)
1436 sector = 0;
1437#elif defined (__alpha__)
1438 sector = 0;
1439 alpha_bootblock_checksum (disklabelbuffer);
1440#else
1441 sector = get_start_sect(xbsd_part);
1442#endif
1443
Eric Andersend3652bf2003-08-06 09:07:37 +00001444 if (fdisk_llseek (fd, (fdisk_loff_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001445 fdisk_fatal (unable_to_seek);
1446 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1447 fdisk_fatal (unable_to_write);
1448
1449#if defined (__alpha__)
1450 printf (_("Bootstrap installed on %s.\n"), disk_device);
1451#else
1452 printf (_("Bootstrap installed on %s.\n"),
1453 partname (disk_device, xbsd_part_index+1, 0));
1454#endif
1455
1456 sync_disks ();
1457}
1458
1459static void
1460xbsd_change_fstype (void)
1461{
1462 int i;
1463
1464 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1465 xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
1466}
1467
1468static int
1469xbsd_get_part_index (int max)
1470{
1471 char prompt[256];
1472 char l;
1473
1474 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1475 do
1476 l = tolower (read_char (prompt));
1477 while (l < 'a' || l > 'a' + max - 1);
1478 return l - 'a';
1479}
1480
1481static int
1482xbsd_check_new_partition (int *i) {
1483
1484 /* room for more? various BSD flavours have different maxima */
1485 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1486 int t;
1487
1488 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1489 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1490 break;
1491
1492 if (t == BSD_MAXPARTITIONS) {
1493 fprintf (stderr, _("The maximum number of partitions "
1494 "has been created\n"));
1495 return 0;
1496 }
1497 }
1498
1499 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1500
1501 if (*i >= xbsd_dlabel.d_npartitions)
1502 xbsd_dlabel.d_npartitions = (*i) + 1;
1503
1504 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1505 fprintf (stderr, _("This partition already exists.\n"));
1506 return 0;
1507 }
1508
1509 return 1;
1510}
1511
1512static void
1513xbsd_list_types (void) {
1514 list_types (xbsd_fstypes);
1515}
1516
1517static u_short
1518xbsd_dkcksum (struct xbsd_disklabel *lp) {
1519 u_short *start, *end;
1520 u_short sum = 0;
1521
1522 start = (u_short *) lp;
1523 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1524 while (start < end)
1525 sum ^= *start++;
1526 return sum;
1527}
1528
1529static int
1530xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) {
1531 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001532
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001533 get_geometry ();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001534 bzero (d, sizeof (struct xbsd_disklabel));
1535
1536 d -> d_magic = BSD_DISKMAGIC;
1537
1538 if (strncmp (disk_device, "/dev/sd", 7) == 0)
1539 d -> d_type = BSD_DTYPE_SCSI;
1540 else
1541 d -> d_type = BSD_DTYPE_ST506;
1542
1543#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
1544 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
1545#endif
1546
1547#if !defined (__alpha__)
1548 d -> d_flags = BSD_D_DOSPART;
1549#else
1550 d -> d_flags = 0;
1551#endif
1552 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001553 d -> d_nsectors = sectors; /* sectors/track */
1554 d -> d_ntracks = heads; /* tracks/cylinder (heads) */
1555 d -> d_ncylinders = cylinders;
1556 d -> d_secpercyl = sectors * heads;/* sectors/cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001557 if (d -> d_secpercyl == 0)
1558 d -> d_secpercyl = 1; /* avoid segfaults */
1559 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1560
1561 d -> d_rpm = 3600;
1562 d -> d_interleave = 1;
1563 d -> d_trackskew = 0;
1564 d -> d_cylskew = 0;
1565 d -> d_headswitch = 0;
1566 d -> d_trkseek = 0;
1567
1568 d -> d_magic2 = BSD_DISKMAGIC;
1569 d -> d_bbsize = BSD_BBSIZE;
1570 d -> d_sbsize = BSD_SBSIZE;
1571
1572#if !defined (__alpha__)
1573 d -> d_npartitions = 4;
1574 pp = &d -> d_partitions[2]; /* Partition C should be
1575 the NetBSD partition */
1576 pp -> p_offset = get_start_sect(p);
1577 pp -> p_size = get_nr_sects(p);
1578 pp -> p_fstype = BSD_FS_UNUSED;
1579 pp = &d -> d_partitions[3]; /* Partition D should be
1580 the whole disk */
1581 pp -> p_offset = 0;
1582 pp -> p_size = d -> d_secperunit;
1583 pp -> p_fstype = BSD_FS_UNUSED;
1584#elif defined (__alpha__)
1585 d -> d_npartitions = 3;
1586 pp = &d -> d_partitions[2]; /* Partition C should be
1587 the whole disk */
1588 pp -> p_offset = 0;
1589 pp -> p_size = d -> d_secperunit;
1590 pp -> p_fstype = BSD_FS_UNUSED;
1591#endif
1592
1593 return 1;
1594}
1595
1596/*
1597 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1598 * If it has the right magic, return 1.
1599 */
1600static int
1601xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1602{
1603 int t, sector;
1604
1605 /* p is used only to get the starting sector */
1606#if !defined (__alpha__)
1607 sector = (p ? get_start_sect(p) : 0);
1608#elif defined (__alpha__)
1609 sector = 0;
1610#endif
1611
Eric Andersend3652bf2003-08-06 09:07:37 +00001612 if (fdisk_llseek (fd, (fdisk_loff_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001613 fdisk_fatal (unable_to_seek);
1614 if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
1615 fdisk_fatal (unable_to_read);
1616
1617 bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1618 d, sizeof (struct xbsd_disklabel));
1619
1620 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
1621 return 0;
1622
1623 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1624 d -> d_partitions[t].p_size = 0;
1625 d -> d_partitions[t].p_offset = 0;
1626 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
1627 }
1628
1629 if (d -> d_npartitions > BSD_MAXPARTITIONS)
1630 fprintf (stderr, _("Warning: too many partitions "
1631 "(%d, maximum is %d).\n"),
1632 d -> d_npartitions, BSD_MAXPARTITIONS);
1633 return 1;
1634}
1635
1636static int
1637xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1638{
Eric Andersen040f4402003-07-30 08:40:37 +00001639 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001640
1641#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1642 sector = get_start_sect(p) + BSD_LABELSECTOR;
1643#else
1644 sector = BSD_LABELSECTOR;
1645#endif
1646
1647 d -> d_checksum = 0;
1648 d -> d_checksum = xbsd_dkcksum (d);
1649
1650 /* This is necessary if we want to write the bootstrap later,
1651 otherwise we'd write the old disklabel with the bootstrap.
1652 */
1653 bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1654 sizeof (struct xbsd_disklabel));
1655
1656#if defined (__alpha__) && BSD_LABELSECTOR == 0
1657 alpha_bootblock_checksum (disklabelbuffer);
Eric Andersend3652bf2003-08-06 09:07:37 +00001658 if (fdisk_llseek (fd, (fdisk_loff_t) 0, SEEK_SET) == -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001659 fdisk_fatal (unable_to_seek);
1660 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1661 fdisk_fatal (unable_to_write);
1662#else
Eric Andersend3652bf2003-08-06 09:07:37 +00001663 if (fdisk_llseek (fd, (fdisk_loff_t) sector * SECTOR_SIZE + BSD_LABELOFFSET,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001664 SEEK_SET) == -1)
1665 fdisk_fatal (unable_to_seek);
1666 if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel)))
1667 fdisk_fatal (unable_to_write);
1668#endif
1669
1670 sync_disks ();
1671
1672 return 1;
1673}
1674
1675
1676#if !defined (__alpha__)
1677static int
1678xbsd_translate_fstype (int linux_type)
1679{
1680 switch (linux_type)
1681 {
1682 case 0x01: /* DOS 12-bit FAT */
1683 case 0x04: /* DOS 16-bit <32M */
1684 case 0x06: /* DOS 16-bit >=32M */
1685 case 0xe1: /* DOS access */
1686 case 0xe3: /* DOS R/O */
1687 case 0xf2: /* DOS secondary */
1688 return BSD_FS_MSDOS;
1689 case 0x07: /* OS/2 HPFS */
1690 return BSD_FS_HPFS;
1691 default:
1692 return BSD_FS_OTHER;
1693 }
1694}
1695
1696static void
1697xbsd_link_part (void)
1698{
1699 int k, i;
1700 struct partition *p;
1701
1702 k = get_partition (1, partitions);
1703
1704 if (!xbsd_check_new_partition (&i))
1705 return;
1706
1707 p = get_part_table(k);
1708
1709 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1710 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1711 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1712}
1713#endif
1714
1715#if defined (__alpha__)
1716
1717#if !defined(__GLIBC__)
1718typedef unsigned long long u_int64_t;
1719#endif
1720
1721static void
1722alpha_bootblock_checksum (char *boot)
1723{
1724 u_int64_t *dp, sum;
1725 int i;
1726
1727 dp = (u_int64_t *)boot;
1728 sum = 0;
1729 for (i = 0; i < 63; i++)
1730 sum += dp[i];
1731 dp[63] = sum;
1732}
1733#endif /* __alpha__ */
1734
1735#endif /* OSF_LABEL */
1736
1737#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1738static inline unsigned short
1739__swap16(unsigned short x) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001740 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001741}
1742
Eric Andersenacd244a2002-12-11 03:49:33 +00001743static inline uint32_t
1744__swap32(uint32_t x) {
Eric Andersen040f4402003-07-30 08:40:37 +00001745 return (((x & 0xFF) << 24) |
1746 ((x & 0xFF00) << 8) |
1747 ((x & 0xFF0000) >> 8) |
1748 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001749}
1750#endif
1751
1752#ifdef CONFIG_FEATURE_SGI_LABEL
1753/*
1754 *
1755 * fdisksgilabel.c
1756 *
1757 * Copyright (C) Andreas Neuper, Sep 1998.
1758 * This file may be modified and redistributed under
1759 * the terms of the GNU Public License.
1760 *
1761 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1762 * Internationalization
1763 */
1764
1765
1766static int sgi_other_endian;
1767static int debug;
1768static short sgi_volumes=1;
1769
1770/*
1771 * only dealing with free blocks here
1772 */
1773
Eric Andersen040f4402003-07-30 08:40:37 +00001774typedef struct { unsigned int first; unsigned int last; } freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001775static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1776
1777static void
Eric Andersen040f4402003-07-30 08:40:37 +00001778setfreelist(int i, unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001779 freelist[i].first = f;
1780 freelist[i].last = l;
1781}
1782
1783static void
Eric Andersen040f4402003-07-30 08:40:37 +00001784add2freelist(unsigned int f, unsigned int l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001785 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001786 for ( ; i < 17 ; i++)
1787 if (freelist[i].last == 0)
1788 break;
1789 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001790}
1791
1792static void
1793clearfreelist(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00001794 int i;
1795
1796 for (i = 0; i < 17 ; i++)
1797 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001798}
1799
Eric Andersen040f4402003-07-30 08:40:37 +00001800static unsigned int
1801isinfreelist(unsigned int b) {
1802 int i;
1803
1804 for (i = 0; i < 17 ; i++)
1805 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001806 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001807 return 0;
1808}
1809 /* return last vacant block of this stride (never 0). */
1810 /* the '>=' is not quite correct, but simplifies the code */
1811/*
1812 * end of free blocks section
1813 */
1814
1815static const struct systypes sgi_sys_types[] = {
1816/* SGI_VOLHDR */ {"\x00" "SGI volhdr" },
1817/* 0x01 */ {"\x01" "SGI trkrepl" },
1818/* 0x02 */ {"\x02" "SGI secrepl" },
1819/* SGI_SWAP */ {"\x03" "SGI raw" },
1820/* 0x04 */ {"\x04" "SGI bsd" },
1821/* 0x05 */ {"\x05" "SGI sysv" },
1822/* ENTIRE_DISK */ {"\x06" "SGI volume" },
1823/* SGI_EFS */ {"\x07" "SGI efs" },
1824/* 0x08 */ {"\x08" "SGI lvol" },
1825/* 0x09 */ {"\x09" "SGI rlvol" },
1826/* SGI_XFS */ {"\x0a" "SGI xfs" },
1827/* SGI_XFSLOG */ {"\x0b" "SGI xfslog" },
1828/* SGI_XLV */ {"\x0c" "SGI xlv" },
1829/* SGI_XVM */ {"\x0d" "SGI xvm" },
1830/* LINUX_SWAP */ {"\x82" "Linux swap" },
1831/* LINUX_NATIVE */ {"\x83" "Linux native" },
1832/* LINUX_LVM */ {"\x8d" "Linux LVM" },
1833/* LINUX_RAID */ {"\xfd" "Linux RAID" },
1834 { NULL }
1835};
1836
1837
1838static int
1839sgi_get_nsect(void) {
1840 return SGI_SSWAP16(sgilabel->devparam.nsect);
1841}
1842
1843static int
1844sgi_get_ntrks(void) {
1845 return SGI_SSWAP16(sgilabel->devparam.ntrks);
1846}
1847
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001848static void
1849sgi_nolabel(void) {
1850 sgilabel->magic = 0;
1851 sgi_label = 0;
1852 partitions = 4;
1853}
1854
1855static unsigned int
Eric Andersen040f4402003-07-30 08:40:37 +00001856two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001857 int i=0;
1858 unsigned int sum=0;
1859
Eric Andersen040f4402003-07-30 08:40:37 +00001860 size /= sizeof(unsigned int);
1861 for (i = 0; i < size; i++)
1862 sum -= SGI_SSWAP32(base[i]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001863 return sum;
1864}
1865
1866static int
1867check_sgi_label(void) {
1868 if (sizeof(sgilabel) > 512) {
1869 fprintf(stderr,
1870 _("According to MIPS Computer Systems, Inc the "
1871 "Label must not contain more than 512 bytes\n"));
1872 exit(1);
1873 }
1874
1875 if (sgilabel->magic != SGI_LABEL_MAGIC &&
1876 sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1877 sgi_label = 0;
1878 sgi_other_endian = 0;
1879 return 0;
1880 }
1881
1882 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1883 /*
1884 * test for correct checksum
1885 */
Eric Andersen040f4402003-07-30 08:40:37 +00001886 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1887 sizeof(*sgilabel))) {
1888 fprintf(stderr,
1889 _("Detected sgi disklabel with wrong checksum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001890 }
1891 update_units();
1892 sgi_label = 1;
1893 partitions= 16;
1894 sgi_volumes = 15;
1895 return 1;
1896}
1897
Eric Andersen040f4402003-07-30 08:40:37 +00001898static unsigned int
1899sgi_get_start_sector(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001900 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1901}
1902
Eric Andersen040f4402003-07-30 08:40:37 +00001903static unsigned int
1904sgi_get_num_sectors(int i) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001905 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1906}
1907
1908static int
Eric Andersen040f4402003-07-30 08:40:37 +00001909sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001910{
1911 return SGI_SSWAP32(sgilabel->partitions[i].id);
1912}
1913
1914static int
1915sgi_get_bootpartition(void)
1916{
1917 return SGI_SSWAP16(sgilabel->boot_part);
1918}
1919
1920static int
1921sgi_get_swappartition(void)
1922{
1923 return SGI_SSWAP16(sgilabel->swap_part);
1924}
1925
1926static void
Eric Andersen040f4402003-07-30 08:40:37 +00001927sgi_list_table(int xtra) {
Eric Andersen99a75d12003-08-08 20:04:56 +00001928 int i, w, wd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001929 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001930
Eric Andersen040f4402003-07-30 08:40:37 +00001931 if(xtra) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001932 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1933 "%d cylinders, %d physical cylinders\n"
1934 "%d extra sects/cyl, interleave %d:1\n"
1935 "%s\n"
1936 "Units = %s of %d * 512 bytes\n\n"),
1937 disk_device, heads, sectors, cylinders,
1938 SGI_SSWAP16(sgiparam.pcylcount),
1939 SGI_SSWAP16(sgiparam.sparecyl),
1940 SGI_SSWAP16(sgiparam.ilfact),
1941 (char *)sgilabel,
1942 str_units(PLURAL), units_per_sector);
1943 } else {
1944 printf( _("\nDisk %s (SGI disk label): "
1945 "%d heads, %d sectors, %d cylinders\n"
1946 "Units = %s of %d * 512 bytes\n\n"),
1947 disk_device, heads, sectors, cylinders,
1948 str_units(PLURAL), units_per_sector );
1949 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001950
1951 w = strlen(disk_device);
1952 wd = strlen(_("Device"));
1953 if (w < wd)
1954 w = wd;
1955
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001956 printf(_("----- partitions -----\n"
1957 "Pt# %*s Info Start End Sectors Id System\n"),
Eric Andersen99a75d12003-08-08 20:04:56 +00001958 w + 2, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001959 for (i = 0 ; i < partitions; i++) {
1960 if( sgi_get_num_sectors(i) || debug ) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001961 uint32_t start = sgi_get_start_sector(i);
1962 uint32_t len = sgi_get_num_sectors(i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001963 kpi++; /* only count nonempty partitions */
1964 printf(
1965 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1966/* fdisk part number */ i+1,
Eric Andersen99a75d12003-08-08 20:04:56 +00001967/* device */ partname(disk_device, kpi, w+3),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001968/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1969/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1970/* start */ (long) scround(start),
1971/* end */ (long) scround(start+len)-1,
1972/* no odd flag on end */ (long) len,
1973/* type id */ sgi_get_sysid(i),
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001974/* type name */ partition_type(sgi_get_sysid(i)));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001975 }
1976 }
1977 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1978 "----- Directory Entries -----\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00001979 sgilabel->boot_file);
1980 for (i = 0 ; i < sgi_volumes; i++) {
1981 if (sgilabel->directory[i].vol_file_size) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001982 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1983 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001984 char*name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001985
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001986 printf(_("%2d: %-10s sector%5u size%8u\n"),
1987 i, name, (unsigned int) start, (unsigned int) len);
1988 }
1989 }
1990}
1991
1992static void
1993sgi_set_bootpartition( int i )
1994{
1995 sgilabel->boot_part = SGI_SSWAP16(((short)i));
1996}
1997
Eric Andersen040f4402003-07-30 08:40:37 +00001998static unsigned int
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001999sgi_get_lastblock(void) {
2000 return heads * sectors * cylinders;
2001}
2002
2003static void
2004sgi_set_swappartition( int i ) {
2005 sgilabel->swap_part = SGI_SSWAP16(((short)i));
2006}
2007
2008static int
Eric Andersen040f4402003-07-30 08:40:37 +00002009sgi_check_bootfile(const char* aFile) {
2010
2011 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
2012 printf(_("\nInvalid Bootfile!\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002013 "\tThe bootfile must be an absolute non-zero pathname,\n"
Eric Andersen040f4402003-07-30 08:40:37 +00002014 "\te.g. \"/unix\" or \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002015 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002016 } else {
2017 if (strlen(aFile) > 16) {
2018 printf(_("\n\tName of Bootfile too long: "
2019 "16 bytes maximum.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002020 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002021 } else {
2022 if (aFile[0] != '/') {
2023 printf(_("\n\tBootfile must have a "
2024 "fully qualified pathname.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002025 return 0;
2026 }
Eric Andersen040f4402003-07-30 08:40:37 +00002027 }
2028 }
2029 if (strncmp(aFile, sgilabel->boot_file, 16)) {
2030 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
2031 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002032 /* filename is correct and did change */
2033 return 1;
2034 }
2035 return 0; /* filename did not change */
2036}
2037
2038static const char *
2039sgi_get_bootfile(void) {
2040 return sgilabel->boot_file;
2041}
2042
2043static void
Eric Andersen040f4402003-07-30 08:40:37 +00002044sgi_set_bootfile(const char* aFile) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002045 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002046
2047 if (sgi_check_bootfile(aFile)) {
2048 while (i < 16) {
2049 if ((aFile[i] != '\n') /* in principle caught again by next line */
2050 && (strlen(aFile) > i))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002051 sgilabel->boot_file[i] = aFile[i];
2052 else
2053 sgilabel->boot_file[i] = 0;
2054 i++;
2055 }
Eric Andersen040f4402003-07-30 08:40:37 +00002056 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002057 }
2058}
2059
2060static void
2061create_sgiinfo(void)
2062{
2063 /* I keep SGI's habit to write the sgilabel to the second block */
Eric Andersen040f4402003-07-30 08:40:37 +00002064 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
2065 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
2066 strncpy(sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002067}
2068
Eric Andersen040f4402003-07-30 08:40:37 +00002069static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002070
2071static void
Eric Andersen040f4402003-07-30 08:40:37 +00002072sgi_write_table(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002073 sgilabel->csum = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002074 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002075 (unsigned int*)sgilabel,
Eric Andersen040f4402003-07-30 08:40:37 +00002076 sizeof(*sgilabel)));
2077 assert(two_s_complement_32bit_sum(
2078 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
2079 if (lseek(fd, 0, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002080 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002081 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002082 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002083 if (! strncmp(sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002084 /*
Eric Andersen040f4402003-07-30 08:40:37 +00002085 * keep this habit of first writing the "sgilabel".
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002086 * I never tested whether it works without (AN 981002).
2087 */
Eric Andersen040f4402003-07-30 08:40:37 +00002088 sgiinfo *info = fill_sgiinfo();
2089 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
Eric Andersend3652bf2003-08-06 09:07:37 +00002090 if (fdisk_llseek(fd, (long long)infostartblock*
Eric Andersen040f4402003-07-30 08:40:37 +00002091 SECTOR_SIZE, SEEK_SET) < 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002092 fdisk_fatal(unable_to_seek);
Eric Andersen040f4402003-07-30 08:40:37 +00002093 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002094 fdisk_fatal(unable_to_write);
Eric Andersen040f4402003-07-30 08:40:37 +00002095 free(info);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002096 }
2097}
2098
2099static int
Eric Andersen040f4402003-07-30 08:40:37 +00002100compare_start(int *x, int *y) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002101 /*
2102 * sort according to start sectors
2103 * and prefers largest partition:
2104 * entry zero is entire disk entry
2105 */
Eric Andersen040f4402003-07-30 08:40:37 +00002106 unsigned int i = *x;
2107 unsigned int j = *y;
2108 unsigned int a = sgi_get_start_sector(i);
2109 unsigned int b = sgi_get_start_sector(j);
2110 unsigned int c = sgi_get_num_sectors(i);
2111 unsigned int d = sgi_get_num_sectors(j);
2112
2113 if (a == b)
2114 return (d > c) ? 1 : (d == c) ? 0 : -1;
2115 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002116}
2117
2118
2119static int
Eric Andersen040f4402003-07-30 08:40:37 +00002120verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002121{
2122 int Index[16]; /* list of valid partitions */
2123 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
Eric Andersen040f4402003-07-30 08:40:37 +00002124 int entire = 0, i = 0;
2125 unsigned int start = 0;
2126 long long gap = 0; /* count unused blocks */
2127 unsigned int lastblock = sgi_get_lastblock();
2128
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002129 clearfreelist();
Eric Andersen040f4402003-07-30 08:40:37 +00002130 for (i=0; i<16; i++) {
2131 if (sgi_get_num_sectors(i) != 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002132 Index[sortcount++]=i;
Eric Andersen040f4402003-07-30 08:40:37 +00002133 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2134 if (entire++ == 1) {
2135 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002136 printf(_("More than one entire disk entry present.\n"));
2137 }
2138 }
2139 }
2140 }
Eric Andersen040f4402003-07-30 08:40:37 +00002141 if (sortcount == 0) {
2142 if (verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002143 printf(_("No partitions defined\n"));
Eric Andersen040f4402003-07-30 08:40:37 +00002144 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002145 }
Eric Andersen040f4402003-07-30 08:40:37 +00002146 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2147 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2148 if ((Index[0] != 10) && verbose)
2149 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2150 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2151 printf(_("The entire disk partition should start "
2152 "at block 0,\n"
2153 "not at diskblock %d.\n"),
2154 sgi_get_start_sector(Index[0]));
2155 if (debug) /* I do not understand how some disks fulfil it */
2156 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2157 printf(_("The entire disk partition is only %d diskblock large,\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002158 "but the disk is %d diskblocks long.\n"),
Eric Andersen040f4402003-07-30 08:40:37 +00002159 sgi_get_num_sectors(Index[0]), lastblock);
2160 lastblock = sgi_get_num_sectors(Index[0]);
2161 } else {
2162 if (verbose)
2163 printf(_("One Partition (#11) should cover the entire disk.\n"));
2164 if (debug>2)
2165 printf("sysid=%d\tpartition=%d\n",
2166 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002167 }
Eric Andersen040f4402003-07-30 08:40:37 +00002168 for (i=1, start=0; i<sortcount; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002169 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
Eric Andersen040f4402003-07-30 08:40:37 +00002170
2171 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2172 if (debug) /* I do not understand how some disks fulfil it */
2173 if (verbose)
2174 printf(_("Partition %d does not start on cylinder boundary.\n"),
2175 Index[i]+1);
2176 }
2177 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2178 if (debug) /* I do not understand how some disks fulfil it */
2179 if (verbose)
2180 printf(_("Partition %d does not end on cylinder boundary.\n"),
2181 Index[i]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002182 }
2183 /* We cannot handle several "entire disk" entries. */
Eric Andersen040f4402003-07-30 08:40:37 +00002184 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2185 if (start > sgi_get_start_sector(Index[i])) {
2186 if (verbose)
2187 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002188 Index[i-1]+1, Index[i]+1,
Eric Andersen040f4402003-07-30 08:40:37 +00002189 start - sgi_get_start_sector(Index[i]));
2190 if (gap > 0) gap = -gap;
2191 if (gap == 0) gap = -1;
2192 }
2193 if (start < sgi_get_start_sector(Index[i])) {
2194 if (verbose)
2195 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2196 sgi_get_start_sector(Index[i]) - start,
2197 start, sgi_get_start_sector(Index[i])-1);
2198 gap += sgi_get_start_sector(Index[i]) - start;
2199 add2freelist(start, sgi_get_start_sector(Index[i]));
2200 }
2201 start = sgi_get_start_sector(Index[i])
2202 + sgi_get_num_sectors(Index[i]);
2203 if (debug > 1) {
2204 if (verbose)
2205 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002206 sgi_get_start_sector(Index[i]),
2207 sgi_get_num_sectors(Index[i]),
Eric Andersen040f4402003-07-30 08:40:37 +00002208 sgi_get_sysid(Index[i]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002209 }
2210 }
Eric Andersen040f4402003-07-30 08:40:37 +00002211 if (start < lastblock) {
2212 if (verbose)
2213 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2214 lastblock - start, start, lastblock-1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002215 gap += lastblock - start;
Eric Andersen040f4402003-07-30 08:40:37 +00002216 add2freelist(start, lastblock);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002217 }
2218 /*
2219 * Done with arithmetics
2220 * Go for details now
2221 */
Eric Andersen040f4402003-07-30 08:40:37 +00002222 if (verbose) {
2223 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2224 printf(_("\nThe boot partition does not exist.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002225 }
Eric Andersen040f4402003-07-30 08:40:37 +00002226 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2227 printf(_("\nThe swap partition does not exist.\n"));
2228 } else {
2229 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2230 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2231 printf(_("\nThe swap partition has no swap type.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002232 }
Eric Andersen040f4402003-07-30 08:40:37 +00002233 if (sgi_check_bootfile("/unix"))
2234 printf(_("\tYou have chosen an unusual boot file name.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002235 }
Eric Andersen040f4402003-07-30 08:40:37 +00002236 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002237}
2238
2239static int
2240sgi_gaps(void) {
2241 /*
2242 * returned value is:
2243 * = 0 : disk is properly filled to the rim
2244 * < 0 : there is an overlap
2245 * > 0 : there is still some vacant space
2246 */
2247 return verify_sgi(0);
2248}
2249
2250static void
2251sgi_change_sysid( int i, int sys )
2252{
2253 if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
2254 {
2255 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2256 return;
2257 }
2258 if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2259 && (sgi_get_start_sector(i)<1) )
2260 {
2261 read_chars(
2262 _("It is highly recommended that the partition at offset 0\n"
2263 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2264 "retrieve from its directory standalone tools like sash and fx.\n"
2265 "Only the \"SGI volume\" entire disk section may violate this.\n"
2266 "Type YES if you are sure about tagging this partition differently.\n"));
2267 if (strcmp (line_ptr, _("YES\n")))
2268 return;
2269 }
2270 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2271}
2272
2273/* returns partition index of first entry marked as entire disk */
2274static int
2275sgi_entire(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00002276 int i;
2277
2278 for(i=0; i<16; i++)
2279 if(sgi_get_sysid(i) == SGI_VOLUME)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002280 return i;
2281 return -1;
2282}
2283
2284static void
Eric Andersen040f4402003-07-30 08:40:37 +00002285sgi_set_partition(int i, unsigned int start, unsigned int length, int sys) {
2286
2287 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2288 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2289 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002290 set_changed(i);
Eric Andersen040f4402003-07-30 08:40:37 +00002291 if (sgi_gaps() < 0) /* rebuild freelist */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002292 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2293}
2294
2295static void
2296sgi_set_entire(void) {
2297 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002298
2299 for(n=10; n < partitions; n++) {
2300 if(!sgi_get_num_sectors(n) ) {
2301 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002302 break;
2303 }
2304 }
2305}
2306
2307static void
2308sgi_set_volhdr(void)
2309{
2310 int n;
2311 for( n=8; n<partitions; n++ )
2312 {
2313 if(!sgi_get_num_sectors( n ) )
2314 {
2315 /*
2316 * 5 cylinders is an arbitrary value I like
2317 * IRIX 5.3 stored files in the volume header
2318 * (like sash, symmon, fx, ide) with ca. 3200
2319 * sectors.
2320 */
2321 if( heads * sectors * 5 < sgi_get_lastblock() )
2322 sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
2323 break;
2324 }
2325 }
2326}
2327
2328static void
2329sgi_delete_partition( int i )
2330{
2331 sgi_set_partition( i, 0, 0, 0 );
2332}
2333
2334static void
2335sgi_add_partition( int n, int sys )
2336{
2337 char mesg[256];
Eric Andersen040f4402003-07-30 08:40:37 +00002338 unsigned int first=0, last=0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002339
2340 if( n == 10 ) {
2341 sys = SGI_VOLUME;
2342 } else if ( n == 8 ) {
2343 sys = 0;
2344 }
Eric Andersen040f4402003-07-30 08:40:37 +00002345 if(sgi_get_num_sectors(n)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002346 printf(_("Partition %d is already defined. Delete "
2347 "it before re-adding it.\n"), n + 1);
2348 return;
2349 }
Eric Andersen040f4402003-07-30 08:40:37 +00002350 if( (sgi_entire() == -1) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002351 printf(_("Attempting to generate entire disk entry automatically.\n"));
2352 sgi_set_entire();
2353 sgi_set_volhdr();
2354 }
Eric Andersen040f4402003-07-30 08:40:37 +00002355 if( (sgi_gaps() == 0) && (sys != SGI_VOLUME) ) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002356 printf(_("The entire disk is already covered with partitions.\n"));
2357 return;
2358 }
Eric Andersen040f4402003-07-30 08:40:37 +00002359 if(sgi_gaps() < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002360 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2361 return;
2362 }
2363 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2364 for(;;) {
2365 if(sys == SGI_VOLUME) {
2366 last = sgi_get_lastblock();
2367 first = read_int(0, 0, last-1, 0, mesg);
2368 if( first != 0 ) {
2369 printf(_("It is highly recommended that eleventh partition\n"
2370 "covers the entire disk and is of type `SGI volume'\n"));
2371 }
2372 } else {
2373 first = freelist[0].first;
2374 last = freelist[0].last;
2375 first = read_int(scround(first), scround(first), scround(last)-1,
2376 0, mesg);
2377 }
2378 if (display_in_cyl_units)
2379 first *= units_per_sector;
2380 else
2381 first = first; /* align to cylinder if you know how ... */
2382 if( !last )
2383 last = isinfreelist(first);
2384 if( last == 0 ) {
2385 printf(_("You will get a partition overlap on the disk. "
2386 "Fix it first!\n"));
2387 } else
2388 break;
2389 }
2390 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2391 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2392 scround(first), mesg)+1;
2393 if (display_in_cyl_units)
2394 last *= units_per_sector;
2395 else
2396 last = last; /* align to cylinder if You know how ... */
2397 if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
2398 printf(_("It is highly recommended that eleventh partition\n"
2399 "covers the entire disk and is of type `SGI volume'\n"));
2400 sgi_set_partition( n, first, last-first, sys );
2401}
2402
Eric Andersen040f4402003-07-30 08:40:37 +00002403#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002404static void
2405create_sgilabel(void)
2406{
2407 struct hd_geometry geometry;
Eric Andersen040f4402003-07-30 08:40:37 +00002408 struct {
2409 unsigned int start;
2410 unsigned int nsect;
2411 int sysid;
2412 } old[4];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002413 int i=0;
Eric Andersen040f4402003-07-30 08:40:37 +00002414 long longsectors; /* the number of sectors on the device */
2415 int res; /* the result from the ioctl */
2416 int sec_fac; /* the sector factor */
2417
2418 sec_fac = sector_size / 512; /* determine the sector factor */
2419
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002420 fprintf( stderr,
2421 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2422 "until you decide to write them. After that, of course, the previous\n"
2423 "content will be unrecoverably lost.\n\n"));
2424
2425 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
Eric Andersen040f4402003-07-30 08:40:37 +00002426 res = ioctl(fd, BLKGETSIZE, &longsectors);
2427 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002428 heads = geometry.heads;
2429 sectors = geometry.sectors;
Eric Andersen040f4402003-07-30 08:40:37 +00002430 if (res == 0) {
2431 /* the get device size ioctl was successful */
2432 cylinders = longsectors / (heads * sectors);
2433 cylinders /= sec_fac;
2434 } else {
2435 /* otherwise print error and use truncated version */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002436 cylinders = geometry.cylinders;
Eric Andersen040f4402003-07-30 08:40:37 +00002437 fprintf(stderr,
2438 _("Warning: BLKGETSIZE ioctl failed on %s. "
2439 "Using geometry cylinder value of %d.\n"
2440 "This value may be truncated for devices"
2441 " > 33.8 GB.\n"), disk_device, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002442 }
Eric Andersen040f4402003-07-30 08:40:37 +00002443 }
2444 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002445 old[i].sysid = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00002446 if(valid_part_table_flag(MBRbuffer)) {
2447 if(get_part_table(i)->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002448 old[i].sysid = get_part_table(i)->sys_ind;
Eric Andersen040f4402003-07-30 08:40:37 +00002449 old[i].start = get_start_sect(get_part_table(i));
2450 old[i].nsect = get_nr_sects(get_part_table(i));
2451 printf(_("Trying to keep parameters of partition %d.\n"), i);
2452 if (debug)
2453 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2454 old[i].sysid, old[i].start, old[i].nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002455 }
2456 }
2457 }
Eric Andersen040f4402003-07-30 08:40:37 +00002458
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002459 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2460 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2461 sgilabel->boot_part = SGI_SSWAP16(0);
2462 sgilabel->swap_part = SGI_SSWAP16(1);
2463
2464 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2465 memset(sgilabel->boot_file, 0, 16);
2466 strcpy(sgilabel->boot_file, "/unix");
2467
2468 sgilabel->devparam.skew = (0);
2469 sgilabel->devparam.gap1 = (0);
2470 sgilabel->devparam.gap2 = (0);
2471 sgilabel->devparam.sparecyl = (0);
2472 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2473 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2474 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
2475 /* tracks/cylinder (heads) */
2476 sgilabel->devparam.cmd_tag_queue_depth = (0);
2477 sgilabel->devparam.unused0 = (0);
2478 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2479 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
2480 /* sectors/track */
2481 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2482 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2483 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
2484 IGNORE_ERRORS|RESEEK);
2485 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2486 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2487 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2488 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2489 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2490 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2491 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2492 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2493 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2494 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2495 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2496 sgi_label = 1;
2497 partitions = 16;
2498 sgi_volumes = 15;
2499 sgi_set_entire();
2500 sgi_set_volhdr();
Eric Andersen040f4402003-07-30 08:40:37 +00002501 for (i = 0; i < 4; i++) {
2502 if(old[i].sysid) {
2503 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002504 }
2505 }
2506}
2507
2508static void
2509sgi_set_xcyl(void)
2510{
2511 /* do nothing in the beginning */
2512}
Eric Andersen040f4402003-07-30 08:40:37 +00002513#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002514
2515/* _____________________________________________________________
2516 */
2517
Eric Andersen040f4402003-07-30 08:40:37 +00002518static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002519fill_sgiinfo(void)
2520{
Eric Andersen040f4402003-07-30 08:40:37 +00002521 sgiinfo *info = calloc(1, sizeof(sgiinfo));
2522
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002523 info->magic=SGI_SSWAP32(SGI_INFO_MAGIC);
2524 info->b1=SGI_SSWAP32(-1);
2525 info->b2=SGI_SSWAP16(-1);
2526 info->b3=SGI_SSWAP16(1);
2527 /* You may want to replace this string !!!!!!! */
2528 strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" );
2529 strcpy( info->serial, "0000" );
2530 info->check1816 = SGI_SSWAP16(18*256 +16 );
2531 strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
2532 return info;
2533}
2534#endif /* SGI_LABEL */
2535
2536
2537#ifdef CONFIG_FEATURE_SUN_LABEL
2538/*
2539 * fdisksunlabel.c
2540 *
2541 * I think this is mostly, or entirely, due to
2542 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2543 *
2544 * Merged with fdisk for other architectures, aeb, June 1998.
2545 *
2546 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2547 * Internationalization
2548 */
2549
2550
2551static int sun_other_endian;
2552static int scsi_disk;
2553static int floppy;
2554
2555#ifndef IDE0_MAJOR
2556#define IDE0_MAJOR 3
2557#endif
2558#ifndef IDE1_MAJOR
2559#define IDE1_MAJOR 22
2560#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002561
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002562static void guess_device_type(void) {
2563 struct stat bootstat;
2564
2565 if (fstat (fd, &bootstat) < 0) {
2566 scsi_disk = 0;
2567 floppy = 0;
2568 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002569 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2570 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002571 scsi_disk = 0;
2572 floppy = 0;
2573 } else if (S_ISBLK(bootstat.st_mode)
Eric Andersen040f4402003-07-30 08:40:37 +00002574 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002575 scsi_disk = 0;
2576 floppy = 1;
2577 } else {
2578 scsi_disk = 1;
2579 floppy = 0;
2580 }
2581}
2582
2583static const struct systypes sun_sys_types[] = {
2584/* 0 */ {"\x00" "Empty" },
2585/* 1 */ {"\x01" "Boot" },
2586/* 2 */ {"\x02" "SunOS root" },
2587/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
2588/* 4 */ {"\x04" "SunOS usr" },
2589/* WHOLE_DISK */ {"\x05" "Whole disk" },
2590/* 6 */ {"\x06" "SunOS stand" },
2591/* 7 */ {"\x07" "SunOS var" },
2592/* 8 */ {"\x08" "SunOS home" },
2593/* LINUX_SWAP */ {"\x82" "Linux swap" },
2594/* LINUX_NATIVE */ {"\x83" "Linux native" },
2595/* 0x8e */ {"\x8e" "Linux LVM" },
2596/* New (2.2.x) raid partition with autodetect using persistent superblock */
2597/* 0xfd */ {"\xfd" "Linux raid autodetect" },
2598 { NULL }
2599};
2600
2601
2602static void
2603set_sun_partition(int i, uint start, uint stop, int sysid) {
2604 sunlabel->infos[i].id = sysid;
2605 sunlabel->partitions[i].start_cylinder =
2606 SUN_SSWAP32(start / (heads * sectors));
2607 sunlabel->partitions[i].num_sectors =
2608 SUN_SSWAP32(stop - start);
2609 set_changed(i);
2610}
2611
2612static void
2613sun_nolabel(void) {
2614 sun_label = 0;
2615 sunlabel->magic = 0;
2616 partitions = 4;
2617}
2618
2619static int
2620check_sun_label(void) {
2621 unsigned short *ush;
2622 int csum;
2623
2624 if (sunlabel->magic != SUN_LABEL_MAGIC &&
2625 sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2626 sun_label = 0;
2627 sun_other_endian = 0;
2628 return 0;
2629 }
2630 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2631 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2632 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2633 if (csum) {
2634 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2635 "Probably you'll have to set all the values,\n"
2636 "e.g. heads, sectors, cylinders and partitions\n"
2637 "or force a fresh label (s command in main menu)\n"));
2638 } else {
2639 heads = SUN_SSWAP16(sunlabel->ntrks);
2640 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2641 sectors = SUN_SSWAP16(sunlabel->nsect);
2642 }
2643 update_units();
2644 sun_label = 1;
2645 partitions = 8;
2646 return 1;
2647}
2648
2649static const struct sun_predefined_drives {
2650 const char *vendor;
2651 const char *model;
2652 unsigned short sparecyl;
2653 unsigned short ncyl;
2654 unsigned short nacyl;
2655 unsigned short pcylcount;
2656 unsigned short ntrks;
2657 unsigned short nsect;
2658 unsigned short rspeed;
2659} sun_drives[] = {
2660{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2661{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2662{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2663{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2664{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2665{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2666{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2667{"","SUN0104",1,974,2,1019,6,35,3662},
2668{"","SUN0207",4,1254,2,1272,9,36,3600},
2669{"","SUN0327",3,1545,2,1549,9,46,3600},
2670{"","SUN0340",0,1538,2,1544,6,72,4200},
2671{"","SUN0424",2,1151,2,2500,9,80,4400},
2672{"","SUN0535",0,1866,2,2500,7,80,5400},
2673{"","SUN0669",5,1614,2,1632,15,54,3600},
2674{"","SUN1.0G",5,1703,2,1931,15,80,3597},
2675{"","SUN1.05",0,2036,2,2038,14,72,5400},
2676{"","SUN1.3G",6,1965,2,3500,17,80,5400},
2677{"","SUN2.1G",0,2733,2,3500,19,80,5400},
2678{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2679};
2680
2681static const struct sun_predefined_drives *
2682sun_autoconfigure_scsi(void) {
2683 const struct sun_predefined_drives *p = NULL;
2684
2685#ifdef SCSI_IOCTL_GET_IDLUN
2686 unsigned int id[2];
2687 char buffer[2048];
2688 char buffer2[2048];
2689 FILE *pfd;
2690 char *vendor;
2691 char *model;
2692 char *q;
2693 int i;
2694
2695 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2696 sprintf(buffer,
2697 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2698#if 0
2699 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2700#else
2701 /* This is very wrong (works only if you have one HBA),
2702 but I haven't found a way how to get hostno
2703 from the current kernel */
2704 0,
2705#endif
2706 (id[0]>>16)&0xff,
2707 id[0]&0xff,
2708 (id[0]>>8)&0xff);
2709 pfd = fopen("/proc/scsi/scsi","r");
2710 if (pfd) {
2711 while (fgets(buffer2,2048,pfd)) {
2712 if (!strcmp(buffer, buffer2)) {
2713 if (fgets(buffer2,2048,pfd)) {
2714 q = strstr(buffer2,"Vendor: ");
2715 if (q) {
2716 q += 8;
2717 vendor = q;
2718 q = strstr(q," ");
2719 *q++ = 0; /* truncate vendor name */
2720 q = strstr(q,"Model: ");
2721 if (q) {
2722 *q = 0;
2723 q += 7;
2724 model = q;
2725 q = strstr(q," Rev: ");
2726 if (q) {
2727 *q = 0;
2728 for (i = 0; i < SIZE(sun_drives); i++) {
2729 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2730 continue;
2731 if (!strstr(model, sun_drives[i].model))
2732 continue;
2733 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2734 p = sun_drives + i;
2735 break;
2736 }
2737 }
2738 }
2739 }
2740 }
2741 break;
2742 }
2743 }
2744 fclose(pfd);
2745 }
2746 }
2747#endif
2748 return p;
2749}
2750
2751static void create_sunlabel(void)
2752{
2753 struct hd_geometry geometry;
2754 unsigned int ndiv;
2755 int i;
2756 unsigned char c;
2757 const struct sun_predefined_drives *p = NULL;
2758
2759 fprintf(stderr,
2760 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2761 "until you decide to write them. After that, of course, the previous\n"
2762 "content won't be recoverable.\n\n"));
2763#if BYTE_ORDER == LITTLE_ENDIAN
2764 sun_other_endian = 1;
2765#else
2766 sun_other_endian = 0;
2767#endif
2768 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2769 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2770 if (!floppy) {
2771 puts(_("Drive type\n"
2772 " ? auto configure\n"
2773 " 0 custom (with hardware detected defaults)"));
2774 for (i = 0; i < SIZE(sun_drives); i++) {
2775 printf(" %c %s%s%s\n",
2776 i + 'a', sun_drives[i].vendor,
2777 (*sun_drives[i].vendor) ? " " : "",
2778 sun_drives[i].model);
2779 }
2780 for (;;) {
2781 c = read_char(_("Select type (? for auto, 0 for custom): "));
2782 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2783 p = sun_drives + c - 'a';
2784 break;
2785 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2786 p = sun_drives + c - 'A';
2787 break;
2788 } else if (c == '0') {
2789 break;
2790 } else if (c == '?' && scsi_disk) {
2791 p = sun_autoconfigure_scsi();
2792 if (!p)
2793 printf(_("Autoconfigure failed.\n"));
2794 else
2795 break;
2796 }
2797 }
2798 }
2799 if (!p || floppy) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002800 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002801 heads = geometry.heads;
2802 sectors = geometry.sectors;
2803 cylinders = geometry.cylinders;
2804 } else {
2805 heads = 0;
2806 sectors = 0;
2807 cylinders = 0;
2808 }
2809 if (floppy) {
2810 sunlabel->nacyl = 0;
2811 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2812 sunlabel->rspeed = SUN_SSWAP16(300);
2813 sunlabel->ilfact = SUN_SSWAP16(1);
2814 sunlabel->sparecyl = 0;
2815 } else {
2816 heads = read_int(1,heads,1024,0,_("Heads"));
2817 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2818 if (cylinders)
2819 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2820 else
2821 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2822 sunlabel->nacyl =
2823 SUN_SSWAP16(read_int(0,2,65535,0,
2824 _("Alternate cylinders")));
2825 sunlabel->pcylcount =
2826 SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl),
2827 65535,0,_("Physical cylinders")));
2828 sunlabel->rspeed =
2829 SUN_SSWAP16(read_int(1,5400,100000,0,
2830 _("Rotation speed (rpm)")));
2831 sunlabel->ilfact =
2832 SUN_SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
2833 sunlabel->sparecyl =
2834 SUN_SSWAP16(read_int(0,0,sectors,0,
2835 _("Extra sectors per cylinder")));
2836 }
2837 } else {
2838 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2839 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2840 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2841 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2842 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2843 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2844 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2845 sunlabel->ilfact = SUN_SSWAP16(1);
2846 cylinders = p->ncyl;
2847 heads = p->ntrks;
2848 sectors = p->nsect;
2849 puts(_("You may change all the disk params from the x menu"));
2850 }
2851
2852 snprintf(sunlabel->info, sizeof(sunlabel->info),
2853 "%s%s%s cyl %d alt %d hd %d sec %d",
2854 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2855 p ? p->model
2856 : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2857 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2858
2859 sunlabel->ntrks = SUN_SSWAP16(heads);
2860 sunlabel->nsect = SUN_SSWAP16(sectors);
2861 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2862 if (floppy)
2863 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2864 else {
2865 if (cylinders * heads * sectors >= 150 * 2048) {
2866 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2867 } else
2868 ndiv = cylinders * 2 / 3;
2869 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2870 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2871 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2872 }
2873 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2874 {
2875 unsigned short *ush = (unsigned short *)sunlabel;
2876 unsigned short csum = 0;
2877 while(ush < (unsigned short *)(&sunlabel->csum))
2878 csum ^= *ush++;
2879 sunlabel->csum = csum;
2880 }
2881
2882 set_all_unchanged();
2883 set_changed(0);
2884 get_boot(create_empty_sun);
2885}
2886
2887static void
2888toggle_sunflags(int i, unsigned char mask) {
2889 if (sunlabel->infos[i].flags & mask)
2890 sunlabel->infos[i].flags &= ~mask;
2891 else sunlabel->infos[i].flags |= mask;
2892 set_changed(i);
2893}
2894
2895static void
2896fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) {
2897 int i, continuous = 1;
2898 *start = 0; *stop = cylinders * heads * sectors;
2899 for (i = 0; i < partitions; i++) {
2900 if (sunlabel->partitions[i].num_sectors
2901 && sunlabel->infos[i].id
2902 && sunlabel->infos[i].id != WHOLE_DISK) {
2903 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2904 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2905 if (continuous) {
2906 if (starts[i] == *start)
2907 *start += lens[i];
2908 else if (starts[i] + lens[i] >= *stop)
2909 *stop = starts[i];
2910 else
2911 continuous = 0;
2912 /* There will be probably more gaps
2913 than one, so lets check afterwards */
2914 }
2915 } else {
2916 starts[i] = 0;
2917 lens[i] = 0;
2918 }
2919 }
2920}
2921
2922static uint *verify_sun_starts;
2923
2924static int
2925verify_sun_cmp(int *a, int *b) {
2926 if (*a == -1) return 1;
2927 if (*b == -1) return -1;
2928 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2929 return -1;
2930}
2931
2932static void
2933verify_sun(void) {
2934 uint starts[8], lens[8], start, stop;
2935 int i,j,k,starto,endo;
2936 int array[8];
2937
2938 verify_sun_starts = starts;
2939 fetch_sun(starts,lens,&start,&stop);
2940 for (k = 0; k < 7; k++) {
2941 for (i = 0; i < 8; i++) {
2942 if (k && (lens[i] % (heads * sectors))) {
2943 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2944 }
2945 if (lens[i]) {
2946 for (j = 0; j < i; j++)
2947 if (lens[j]) {
2948 if (starts[j] == starts[i]+lens[i]) {
2949 starts[j] = starts[i]; lens[j] += lens[i];
2950 lens[i] = 0;
2951 } else if (starts[i] == starts[j]+lens[j]){
2952 lens[j] += lens[i];
2953 lens[i] = 0;
2954 } else if (!k) {
2955 if (starts[i] < starts[j]+lens[j] &&
2956 starts[j] < starts[i]+lens[i]) {
2957 starto = starts[i];
2958 if (starts[j] > starto)
2959 starto = starts[j];
2960 endo = starts[i]+lens[i];
2961 if (starts[j]+lens[j] < endo)
2962 endo = starts[j]+lens[j];
2963 printf(_("Partition %d overlaps with others in "
2964 "sectors %d-%d\n"), i+1, starto, endo);
2965 }
2966 }
2967 }
2968 }
2969 }
2970 }
2971 for (i = 0; i < 8; i++) {
2972 if (lens[i])
2973 array[i] = i;
2974 else
2975 array[i] = -1;
2976 }
2977 qsort(array,SIZE(array),sizeof(array[0]),
2978 (int (*)(const void *,const void *)) verify_sun_cmp);
2979 if (array[0] == -1) {
2980 printf(_("No partitions defined\n"));
2981 return;
2982 }
2983 stop = cylinders * heads * sectors;
2984 if (starts[array[0]])
2985 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2986 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2987 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2988 }
2989 start = starts[array[i]]+lens[array[i]];
2990 if (start < stop)
2991 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
2992}
2993
2994static void
2995add_sun_partition(int n, int sys) {
2996 uint start, stop, stop2;
2997 uint starts[8], lens[8];
2998 int whole_disk = 0;
2999
3000 char mesg[256];
3001 int i, first, last;
3002
3003 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
3004 printf(_("Partition %d is already defined. Delete "
3005 "it before re-adding it.\n"), n + 1);
3006 return;
3007 }
3008
3009 fetch_sun(starts,lens,&start,&stop);
3010 if (stop <= start) {
3011 if (n == 2)
3012 whole_disk = 1;
3013 else {
3014 printf(_("Other partitions already cover the whole disk.\nDelete "
3015 "some/shrink them before retry.\n"));
3016 return;
3017 }
3018 }
3019 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
3020 for (;;) {
3021 if (whole_disk)
3022 first = read_int(0, 0, 0, 0, mesg);
3023 else
3024 first = read_int(scround(start), scround(stop)+1,
3025 scround(stop), 0, mesg);
3026 if (display_in_cyl_units)
3027 first *= units_per_sector;
3028 else
3029 /* Starting sector has to be properly aligned */
3030 first = (first + heads * sectors - 1) / (heads * sectors);
3031 if (n == 2 && first != 0)
3032 printf ("\
3033It is highly recommended that the third partition covers the whole disk\n\
3034and is of type `Whole disk'\n");
3035 /* ewt asks to add: "don't start a partition at cyl 0"
3036 However, edmundo@rano.demon.co.uk writes:
3037 "In addition to having a Sun partition table, to be able to
3038 boot from the disc, the first partition, /dev/sdX1, must
3039 start at cylinder 0. This means that /dev/sdX1 contains
3040 the partition table and the boot block, as these are the
3041 first two sectors of the disc. Therefore you must be
3042 careful what you use /dev/sdX1 for. In particular, you must
3043 not use a partition starting at cylinder 0 for Linux swap,
3044 as that would overwrite the partition table and the boot
3045 block. You may, however, use such a partition for a UFS
3046 or EXT2 file system, as these file systems leave the first
3047 1024 bytes undisturbed. */
3048 /* On the other hand, one should not use partitions
3049 starting at block 0 in an md, or the label will
3050 be trashed. */
3051 for (i = 0; i < partitions; i++)
3052 if (lens[i] && starts[i] <= first
3053 && starts[i] + lens[i] > first)
3054 break;
3055 if (i < partitions && !whole_disk) {
3056 if (n == 2 && !first) {
3057 whole_disk = 1;
3058 break;
3059 }
3060 printf(_("Sector %d is already allocated\n"), first);
3061 } else
3062 break;
3063 }
3064 stop = cylinders * heads * sectors;
3065 stop2 = stop;
3066 for (i = 0; i < partitions; i++) {
3067 if (starts[i] > first && starts[i] < stop)
3068 stop = starts[i];
3069 }
3070 snprintf(mesg, sizeof(mesg),
3071 _("Last %s or +size or +sizeM or +sizeK"),
3072 str_units(SINGULAR));
3073 if (whole_disk)
3074 last = read_int(scround(stop2), scround(stop2), scround(stop2),
3075 0, mesg);
3076 else if (n == 2 && !first)
3077 last = read_int(scround(first), scround(stop2), scround(stop2),
3078 scround(first), mesg);
3079 else
3080 last = read_int(scround(first), scround(stop), scround(stop),
3081 scround(first), mesg);
3082 if (display_in_cyl_units)
3083 last *= units_per_sector;
3084 if (n == 2 && !first) {
3085 if (last >= stop2) {
3086 whole_disk = 1;
3087 last = stop2;
3088 } else if (last > stop) {
3089 printf (
3090 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
3091 "%d %s covers some other partition. Your entry has been changed\n"
3092 "to %d %s\n"),
3093 scround(last), str_units(SINGULAR),
3094 scround(stop), str_units(SINGULAR));
3095 last = stop;
3096 }
3097 } else if (!whole_disk && last > stop)
3098 last = stop;
3099
3100 if (whole_disk) sys = WHOLE_DISK;
3101 set_sun_partition(n, first, last, sys);
3102}
3103
3104static void
3105sun_delete_partition(int i) {
Eric Andersen040f4402003-07-30 08:40:37 +00003106 unsigned int nsec;
3107
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003108 if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
3109 !sunlabel->partitions[i].start_cylinder &&
Eric Andersen040f4402003-07-30 08:40:37 +00003110 (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003111 == heads * sectors * cylinders)
3112 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3113 "consider leaving this\n"
3114 "partition as Whole disk (5), starting at 0, with %u "
Eric Andersen040f4402003-07-30 08:40:37 +00003115 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003116 sunlabel->infos[i].id = 0;
3117 sunlabel->partitions[i].num_sectors = 0;
3118}
3119
3120static void
3121sun_change_sysid(int i, int sys) {
3122 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3123 read_chars(
3124 _("It is highly recommended that the partition at offset 0\n"
3125 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3126 "there may destroy your partition table and bootblock.\n"
3127 "Type YES if you're very sure you would like that partition\n"
3128 "tagged with 82 (Linux swap): "));
3129 if (strcmp (line_ptr, _("YES\n")))
3130 return;
3131 }
3132 switch (sys) {
3133 case SUNOS_SWAP:
3134 case LINUX_SWAP:
3135 /* swaps are not mountable by default */
3136 sunlabel->infos[i].flags |= 0x01;
3137 break;
3138 default:
3139 /* assume other types are mountable;
3140 user can change it anyway */
3141 sunlabel->infos[i].flags &= ~0x01;
3142 break;
3143 }
3144 sunlabel->infos[i].id = sys;
3145}
3146
3147static void
3148sun_list_table(int xtra) {
3149 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003150
3151 w = strlen(disk_device);
3152 if (xtra)
3153 printf(
3154 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3155 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3156 "%d extra sects/cyl, interleave %d:1\n"
3157 "%s\n"
3158 "Units = %s of %d * 512 bytes\n\n"),
3159 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3160 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3161 SUN_SSWAP16(sunlabel->pcylcount),
3162 SUN_SSWAP16(sunlabel->sparecyl),
3163 SUN_SSWAP16(sunlabel->ilfact),
3164 (char *)sunlabel,
3165 str_units(PLURAL), units_per_sector);
3166 else
3167 printf(
3168 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3169 "Units = %s of %d * 512 bytes\n\n"),
3170 disk_device, heads, sectors, cylinders,
3171 str_units(PLURAL), units_per_sector);
3172
3173 printf(_("%*s Flag Start End Blocks Id System\n"),
3174 w + 1, _("Device"));
3175 for (i = 0 ; i < partitions; i++) {
3176 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003177 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3178 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003179 printf(
3180 "%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3181/* device */ partname(disk_device, i+1, w),
3182/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
3183 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3184/* start */ (long) scround(start),
3185/* end */ (long) scround(start+len),
3186/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
3187/* type id */ sunlabel->infos[i].id,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003188/* type name */ partition_type(sunlabel->infos[i].id));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003189 }
3190 }
3191}
3192
Eric Andersen040f4402003-07-30 08:40:37 +00003193#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3194
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003195static void
3196sun_set_alt_cyl(void) {
3197 sunlabel->nacyl =
3198 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3199 _("Number of alternate cylinders")));
3200}
3201
3202static void
3203sun_set_ncyl(int cyl) {
3204 sunlabel->ncyl = SUN_SSWAP16(cyl);
3205}
3206
3207static void
3208sun_set_xcyl(void) {
3209 sunlabel->sparecyl =
3210 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3211 _("Extra sectors per cylinder")));
3212}
3213
3214static void
3215sun_set_ilfact(void) {
3216 sunlabel->ilfact =
3217 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3218 _("Interleave factor")));
3219}
3220
3221static void
3222sun_set_rspeed(void) {
3223 sunlabel->rspeed =
3224 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3225 _("Rotation speed (rpm)")));
3226}
3227
3228static void
3229sun_set_pcylcount(void) {
3230 sunlabel->pcylcount =
3231 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3232 _("Number of physical cylinders")));
3233}
Eric Andersen040f4402003-07-30 08:40:37 +00003234#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003235
3236static void
3237sun_write_table(void) {
3238 unsigned short *ush = (unsigned short *)sunlabel;
3239 unsigned short csum = 0;
3240
3241 while(ush < (unsigned short *)(&sunlabel->csum))
3242 csum ^= *ush++;
3243 sunlabel->csum = csum;
3244 if (lseek(fd, 0, SEEK_SET) < 0)
3245 fdisk_fatal(unable_to_seek);
3246 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3247 fdisk_fatal(unable_to_write);
3248}
3249#endif /* SUN_LABEL */
3250
3251/* DOS partition types */
3252
3253static const struct systypes i386_sys_types[] = {
3254 {"\x00" "Empty"},
3255 {"\x01" "FAT12"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003256 {"\x04" "FAT16 <32M"},
3257 {"\x05" "Extended"}, /* DOS 3.3+ extended partition */
3258 {"\x06" "FAT16"}, /* DOS 16-bit >=32M */
3259 {"\x07" "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003260 {"\x0a" "OS/2 Boot Manager"},/* OS/2 Boot Manager */
3261 {"\x0b" "Win95 FAT32"},
3262 {"\x0c" "Win95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
3263 {"\x0e" "Win95 FAT16 (LBA)"},
3264 {"\x0f" "Win95 Ext'd (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003265 {"\x11" "Hidden FAT12"},
3266 {"\x12" "Compaq diagnostics"},
3267 {"\x14" "Hidden FAT16 <32M"},
3268 {"\x16" "Hidden FAT16"},
3269 {"\x17" "Hidden HPFS/NTFS"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003270 {"\x1b" "Hidden Win95 FAT32"},
3271 {"\x1c" "Hidden Win95 FAT32 (LBA)"},
3272 {"\x1e" "Hidden Win95 FAT16 (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003273 {"\x3c" "PartitionMagic recovery"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003274 {"\x41" "PPC PReP Boot"},
3275 {"\x42" "SFS"},
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003276 {"\x63" "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3277 {"\x80" "Old Minix"}, /* Minix 1.4a and earlier */
3278 {"\x81" "Minix / old Linux"},/* Minix 1.4b and later */
3279 {"\x82" "Linux swap"}, /* also Solaris */
3280 {"\x83" "Linux"},
3281 {"\x84" "OS/2 hidden C: drive"},
3282 {"\x85" "Linux extended"},
3283 {"\x86" "NTFS volume set"},
3284 {"\x87" "NTFS volume set"},
3285 {"\x8e" "Linux LVM"},
3286 {"\x9f" "BSD/OS"}, /* BSDI */
3287 {"\xa0" "IBM Thinkpad hibernation"},
3288 {"\xa5" "FreeBSD"}, /* various BSD flavours */
3289 {"\xa6" "OpenBSD"},
3290 {"\xa8" "Darwin UFS"},
3291 {"\xa9" "NetBSD"},
3292 {"\xab" "Darwin boot"},
3293 {"\xb7" "BSDI fs"},
3294 {"\xb8" "BSDI swap"},
3295 {"\xbe" "Solaris boot"},
3296 {"\xeb" "BeOS fs"},
3297 {"\xee" "EFI GPT"}, /* Intel EFI GUID Partition Table */
3298 {"\xef" "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
3299 {"\xf0" "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
3300 {"\xf2" "DOS secondary"}, /* DOS 3.3+ secondary */
3301 {"\xfd" "Linux raid autodetect"},/* New (2.2.x) raid partition with
3302 autodetect using persistent
3303 superblock */
3304#ifdef CONFIG_WEIRD_PARTITION_TYPES
3305 {"\x02" "XENIX root"},
3306 {"\x03" "XENIX usr"},
3307 {"\x08" "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3308 {"\x09" "AIX bootable"}, /* AIX data or Coherent */
3309 {"\x10" "OPUS"},
3310 {"\x18" "AST SmartSleep"},
3311 {"\x24" "NEC DOS"},
3312 {"\x39" "Plan 9"},
3313 {"\x40" "Venix 80286"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003314 {"\x4d" "QNX4.x"},
3315 {"\x4e" "QNX4.x 2nd part"},
3316 {"\x4f" "QNX4.x 3rd part"},
3317 {"\x50" "OnTrack DM"},
3318 {"\x51" "OnTrack DM6 Aux1"}, /* (or Novell) */
3319 {"\x52" "CP/M"}, /* CP/M or Microport SysV/AT */
3320 {"\x53" "OnTrack DM6 Aux3"},
3321 {"\x54" "OnTrackDM6"},
3322 {"\x55" "EZ-Drive"},
3323 {"\x56" "Golden Bow"},
3324 {"\x5c" "Priam Edisk"},
3325 {"\x61" "SpeedStor"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003326 {"\x64" "Novell Netware 286"},
3327 {"\x65" "Novell Netware 386"},
3328 {"\x70" "DiskSecure Multi-Boot"},
3329 {"\x75" "PC/IX"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003330 {"\x93" "Amoeba"},
3331 {"\x94" "Amoeba BBT"}, /* (bad block table) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003332 {"\xa7" "NeXTSTEP"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003333 {"\xbb" "Boot Wizard hidden"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003334 {"\xc1" "DRDOS/sec (FAT-12)"},
3335 {"\xc4" "DRDOS/sec (FAT-16 < 32M)"},
3336 {"\xc6" "DRDOS/sec (FAT-16)"},
3337 {"\xc7" "Syrinx"},
3338 {"\xda" "Non-FS data"},
3339 {"\xdb" "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
3340 Concurrent DOS or CTOS */
3341 {"\xde" "Dell Utility"}, /* Dell PowerEdge Server utilities */
3342 {"\xdf" "BootIt"}, /* BootIt EMBRM */
3343 {"\xe1" "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
3344 extended partition */
3345 {"\xe3" "DOS R/O"}, /* DOS R/O or SpeedStor */
3346 {"\xe4" "SpeedStor"}, /* SpeedStor 16-bit FAT extended
3347 partition < 1024 cyl. */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003348 {"\xf1" "SpeedStor"},
3349 {"\xf4" "SpeedStor"}, /* SpeedStor large partition */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003350 {"\xfe" "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
3351 {"\xff" "BBT"}, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003352#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003353 { 0 }
3354};
3355
3356
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003357
3358/* A valid partition table sector ends in 0x55 0xaa */
3359static unsigned int
3360part_table_flag(const char *b) {
3361 return ((uint) b[510]) + (((uint) b[511]) << 8);
3362}
3363
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003364
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003365#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003366static void
3367write_part_table_flag(char *b) {
3368 b[510] = 0x55;
3369 b[511] = 0xaa;
3370}
3371
3372/* start_sect and nr_sects are stored little endian on all machines */
3373/* moreover, they are not aligned correctly */
3374static void
3375store4_little_endian(unsigned char *cp, unsigned int val) {
3376 cp[0] = (val & 0xff);
3377 cp[1] = ((val >> 8) & 0xff);
3378 cp[2] = ((val >> 16) & 0xff);
3379 cp[3] = ((val >> 24) & 0xff);
3380}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003381#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003382
3383static unsigned int
3384read4_little_endian(const unsigned char *cp) {
3385 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3386 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3387}
3388
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003389#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003390static void
3391set_start_sect(struct partition *p, unsigned int start_sect) {
3392 store4_little_endian(p->start4, start_sect);
3393}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003394#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003395
3396static unsigned int
3397get_start_sect(const struct partition *p) {
3398 return read4_little_endian(p->start4);
3399}
3400
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003401#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003402static void
3403set_nr_sects(struct partition *p, unsigned int nr_sects) {
3404 store4_little_endian(p->size4, nr_sects);
3405}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003406#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003407
3408static unsigned int
3409get_nr_sects(const struct partition *p) {
3410 return read4_little_endian(p->size4);
3411}
3412
3413/* normally O_RDWR, -l option gives O_RDONLY */
3414static int type_open = O_RDWR;
3415
3416
3417static int ext_index, /* the prime extended partition */
3418 listing, /* no aborts for fdisk -l */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003419 dos_compatible_flag = ~0;
3420#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3421static int dos_changed;
3422static int nowarn; /* no warnings for fdisk -l/-s */
3423#endif
3424
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003425
3426
3427static uint user_cylinders, user_heads, user_sectors;
3428static uint pt_heads, pt_sectors;
3429static uint kern_heads, kern_sectors;
3430
3431static uint extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003432
Eric Andersen040f4402003-07-30 08:40:37 +00003433static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003434
3435
3436static jmp_buf listingbuf;
3437
3438static void fdisk_fatal(enum failure why) {
3439 const char *message;
3440
3441 if (listing) {
3442 close(fd);
3443 longjmp(listingbuf, 1);
3444 }
3445
3446 switch (why) {
3447 case unable_to_open:
3448 message = "Unable to open %s\n";
3449 break;
3450 case unable_to_read:
3451 message = "Unable to read %s\n";
3452 break;
3453 case unable_to_seek:
3454 message = "Unable to seek on %s\n";
3455 break;
3456 case unable_to_write:
3457 message = "Unable to write %s\n";
3458 break;
3459 case ioctl_error:
3460 message = "BLKGETSIZE ioctl failed on %s\n";
3461 break;
3462 default:
3463 message = "Fatal error\n";
3464 }
3465
3466 fputc('\n', stderr);
3467 fprintf(stderr, message, disk_device);
3468 exit(1);
3469}
3470
3471static void
3472seek_sector(uint secno) {
Eric Andersend3652bf2003-08-06 09:07:37 +00003473 fdisk_loff_t offset = (fdisk_loff_t) secno * sector_size;
3474 if (fdisk_llseek(fd, offset, SEEK_SET) == (fdisk_loff_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003475 fdisk_fatal(unable_to_seek);
3476}
3477
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003478#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003479static void
3480write_sector(uint secno, char *buf) {
3481 seek_sector(secno);
3482 if (write(fd, buf, sector_size) != sector_size)
3483 fdisk_fatal(unable_to_write);
3484}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003485#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003486
3487/* Allocate a buffer and read a partition table sector */
3488static void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003489read_pte(struct pte *pe, uint offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003490
3491 pe->offset = offset;
3492 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003493 seek_sector(offset);
3494 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3495 fdisk_fatal(unable_to_read);
3496#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003497 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003498#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003499 pe->part_table = pe->ext_pointer = NULL;
3500}
3501
3502static unsigned int
3503get_partition_start(const struct pte *pe) {
3504 return pe->offset + get_start_sect(pe->part_table);
3505}
3506
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003507#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003508/*
3509 * Avoid warning about DOS partitions when no DOS partition was changed.
3510 * Here a heuristic "is probably dos partition".
3511 * We might also do the opposite and warn in all cases except
3512 * for "is probably nondos partition".
3513 */
3514static int
3515is_dos_partition(int t) {
3516 return (t == 1 || t == 4 || t == 6 ||
3517 t == 0x0b || t == 0x0c || t == 0x0e ||
3518 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3519 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3520 t == 0xc1 || t == 0xc4 || t == 0xc6);
3521}
3522
3523static void
3524menu(void) {
3525#ifdef CONFIG_FEATURE_SUN_LABEL
3526 if (sun_label) {
3527 puts(_("Command action"));
3528 puts(_("\ta\ttoggle a read only flag")); /* sun */
3529 puts(_("\tb\tedit bsd disklabel"));
3530 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3531 puts(_("\td\tdelete a partition"));
3532 puts(_("\tl\tlist known partition types"));
3533 puts(_("\tm\tprint this menu"));
3534 puts(_("\tn\tadd a new partition"));
3535 puts(_("\to\tcreate a new empty DOS partition table"));
3536 puts(_("\tp\tprint the partition table"));
3537 puts(_("\tq\tquit without saving changes"));
3538 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3539 puts(_("\tt\tchange a partition's system id"));
3540 puts(_("\tu\tchange display/entry units"));
3541 puts(_("\tv\tverify the partition table"));
3542 puts(_("\tw\twrite table to disk and exit"));
3543#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3544 puts(_("\tx\textra functionality (experts only)"));
3545#endif
3546 } else
3547#endif
3548#ifdef CONFIG_FEATURE_SGI_LABEL
3549 if (sgi_label) {
3550 puts(_("Command action"));
3551 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3552 puts(_("\tb\tedit bootfile entry")); /* sgi */
3553 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3554 puts(_("\td\tdelete a partition"));
3555 puts(_("\tl\tlist known partition types"));
3556 puts(_("\tm\tprint this menu"));
3557 puts(_("\tn\tadd a new partition"));
3558 puts(_("\to\tcreate a new empty DOS partition table"));
3559 puts(_("\tp\tprint the partition table"));
3560 puts(_("\tq\tquit without saving changes"));
3561 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3562 puts(_("\tt\tchange a partition's system id"));
3563 puts(_("\tu\tchange display/entry units"));
3564 puts(_("\tv\tverify the partition table"));
3565 puts(_("\tw\twrite table to disk and exit"));
3566 } else
3567#endif
3568#ifdef CONFIG_FEATURE_AIX_LABEL
3569 if (aix_label) {
3570 puts(_("Command action"));
3571 puts(_("\tm\tprint this menu"));
3572 puts(_("\to\tcreate a new empty DOS partition table"));
3573 puts(_("\tq\tquit without saving changes"));
3574 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3575 } else
3576#endif
3577 {
3578 puts(_("Command action"));
3579 puts(_("\ta\ttoggle a bootable flag"));
3580 puts(_("\tb\tedit bsd disklabel"));
3581 puts(_("\tc\ttoggle the dos compatibility flag"));
3582 puts(_("\td\tdelete a partition"));
3583 puts(_("\tl\tlist known partition types"));
3584 puts(_("\tm\tprint this menu"));
3585 puts(_("\tn\tadd a new partition"));
3586 puts(_("\to\tcreate a new empty DOS partition table"));
3587 puts(_("\tp\tprint the partition table"));
3588 puts(_("\tq\tquit without saving changes"));
3589 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3590 puts(_("\tt\tchange a partition's system id"));
3591 puts(_("\tu\tchange display/entry units"));
3592 puts(_("\tv\tverify the partition table"));
3593 puts(_("\tw\twrite table to disk and exit"));
3594#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3595 puts(_("\tx\textra functionality (experts only)"));
3596#endif
3597 }
3598}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003599#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3600
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003601
3602#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3603static void
3604xmenu(void) {
3605#ifdef CONFIG_FEATURE_SUN_LABEL
3606 if (sun_label) {
3607 puts(_("Command action"));
3608 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3609 puts(_("\tc\tchange number of cylinders"));
3610 puts(_("\td\tprint the raw data in the partition table"));
3611 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3612 puts(_("\th\tchange number of heads"));
3613 puts(_("\ti\tchange interleave factor")); /*sun*/
3614 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3615 puts(_("\tm\tprint this menu"));
3616 puts(_("\tp\tprint the partition table"));
3617 puts(_("\tq\tquit without saving changes"));
3618 puts(_("\tr\treturn to main menu"));
3619 puts(_("\ts\tchange number of sectors/track"));
3620 puts(_("\tv\tverify the partition table"));
3621 puts(_("\tw\twrite table to disk and exit"));
3622 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
3623 } else
3624#endif
3625#ifdef CONFIG_FEATURE_SGI_LABEL
3626 if (sgi_label) {
3627 puts(_("Command action"));
3628 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3629 puts(_("\tc\tchange number of cylinders"));
3630 puts(_("\td\tprint the raw data in the partition table"));
3631 puts(_("\te\tlist extended partitions")); /* !sun */
3632 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3633 puts(_("\th\tchange number of heads"));
3634 puts(_("\tm\tprint this menu"));
3635 puts(_("\tp\tprint the partition table"));
3636 puts(_("\tq\tquit without saving changes"));
3637 puts(_("\tr\treturn to main menu"));
3638 puts(_("\ts\tchange number of sectors/track"));
3639 puts(_("\tv\tverify the partition table"));
3640 puts(_("\tw\twrite table to disk and exit"));
3641 } else
3642#endif
3643#ifdef CONFIG_FEATURE_AIX_LABEL
3644 if (aix_label) {
3645 puts(_("Command action"));
3646 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3647 puts(_("\tc\tchange number of cylinders"));
3648 puts(_("\td\tprint the raw data in the partition table"));
3649 puts(_("\te\tlist extended partitions")); /* !sun */
3650 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3651 puts(_("\th\tchange number of heads"));
3652 puts(_("\tm\tprint this menu"));
3653 puts(_("\tp\tprint the partition table"));
3654 puts(_("\tq\tquit without saving changes"));
3655 puts(_("\tr\treturn to main menu"));
3656 puts(_("\ts\tchange number of sectors/track"));
3657 puts(_("\tv\tverify the partition table"));
3658 puts(_("\tw\twrite table to disk and exit"));
3659 } else
3660#endif
3661 {
3662 puts(_("Command action"));
3663 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3664 puts(_("\tc\tchange number of cylinders"));
3665 puts(_("\td\tprint the raw data in the partition table"));
3666 puts(_("\te\tlist extended partitions")); /* !sun */
3667 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
3668#ifdef CONFIG_FEATURE_SGI_LABEL
3669 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3670#endif
3671 puts(_("\th\tchange number of heads"));
3672 puts(_("\tm\tprint this menu"));
3673 puts(_("\tp\tprint the partition table"));
3674 puts(_("\tq\tquit without saving changes"));
3675 puts(_("\tr\treturn to main menu"));
3676 puts(_("\ts\tchange number of sectors/track"));
3677 puts(_("\tv\tverify the partition table"));
3678 puts(_("\tw\twrite table to disk and exit"));
3679 }
3680}
3681#endif /* ADVANCED mode */
3682
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003683#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003684static const struct systypes *
3685get_sys_types(void) {
3686 return (
3687#ifdef CONFIG_FEATURE_SUN_LABEL
3688 sun_label ? sun_sys_types :
3689#endif
3690#ifdef CONFIG_FEATURE_SGI_LABEL
3691 sgi_label ? sgi_sys_types :
3692#endif
3693 i386_sys_types);
3694}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003695#else
3696#define get_sys_types() i386_sys_types
3697#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003698
3699static const char *partition_type(unsigned char type)
3700{
3701 int i;
3702 const struct systypes *types = get_sys_types();
3703
3704 for (i=0; types[i].name; i++)
3705 if (types[i].name[0] == type)
3706 return types[i].name + 1;
3707
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003708 return _("Unknown");
3709}
3710
3711
3712#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3713static int
3714get_sysid(int i) {
3715 return (
3716#ifdef CONFIG_FEATURE_SUN_LABEL
3717 sun_label ? sunlabel->infos[i].id :
3718#endif
3719#ifdef CONFIG_FEATURE_SGI_LABEL
3720 sgi_label ? sgi_get_sysid(i) :
3721#endif
3722 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003723}
3724
3725void list_types(const struct systypes *sys)
3726{
3727 uint last[4], done = 0, next = 0, size;
3728 int i;
3729
3730 for (i = 0; sys[i].name; i++);
3731 size = i;
3732
3733 for (i = 3; i >= 0; i--)
3734 last[3 - i] = done += (size + i - done) / (i + 1);
3735 i = done = 0;
3736
3737 do {
3738 printf("%c%2x %-15.15s", i ? ' ' : '\n',
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003739 sys[next].name[0], partition_type(sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003740 next = last[i++] + done;
3741 if (i > 3 || next >= last[i]) {
3742 i = 0;
3743 next = ++done;
3744 }
3745 } while (done < last[0]);
3746 putchar('\n');
3747}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003748#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003749
3750static int
3751is_cleared_partition(const struct partition *p) {
3752 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3753 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3754 get_start_sect(p) || get_nr_sects(p));
3755}
3756
3757static void
3758clear_partition(struct partition *p) {
3759 if (!p)
3760 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003761 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003762}
3763
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003764#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003765static void
3766set_partition(int i, int doext, uint start, uint stop, int sysid) {
3767 struct partition *p;
3768 uint offset;
3769
3770 if (doext) {
3771 p = ptes[i].ext_pointer;
3772 offset = extended_offset;
3773 } else {
3774 p = ptes[i].part_table;
3775 offset = ptes[i].offset;
3776 }
3777 p->boot_ind = 0;
3778 p->sys_ind = sysid;
3779 set_start_sect(p, start - offset);
3780 set_nr_sects(p, stop - start + 1);
3781 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3782 start = heads*sectors*1024 - 1;
3783 set_hsc(p->head, p->sector, p->cyl, start);
3784 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3785 stop = heads*sectors*1024 - 1;
3786 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3787 ptes[i].changed = 1;
3788}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003789#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003790
3791static int
3792test_c(const char **m, const char *mesg) {
3793 int val = 0;
3794 if (!*m)
3795 fprintf(stderr, _("You must set"));
3796 else {
3797 fprintf(stderr, " %s", *m);
3798 val = 1;
3799 }
3800 *m = mesg;
3801 return val;
3802}
3803
3804static int
3805warn_geometry(void) {
3806 const char *m = NULL;
3807 int prev = 0;
3808
3809 if (!heads)
3810 prev = test_c(&m, _("heads"));
3811 if (!sectors)
3812 prev = test_c(&m, _("sectors"));
3813 if (!cylinders)
3814 prev = test_c(&m, _("cylinders"));
3815 if (!m)
3816 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003817
3818 fprintf(stderr, "%s%s.\n"
3819#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3820 "You can do this from the extra functions menu.\n"
3821#endif
3822 , prev ? _(" and ") : " ", m);
3823
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003824 return 1;
3825}
3826
3827static void update_units(void)
3828{
3829 int cyl_units = heads * sectors;
3830
3831 if (display_in_cyl_units && cyl_units)
3832 units_per_sector = cyl_units;
3833 else
3834 units_per_sector = 1; /* in sectors */
3835}
3836
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003837#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003838static void
3839warn_cylinders(void) {
3840 if (dos_label && cylinders > 1024 && !nowarn)
3841 fprintf(stderr, _("\n"
3842"The number of cylinders for this disk is set to %d.\n"
3843"There is nothing wrong with that, but this is larger than 1024,\n"
3844"and could in certain setups cause problems with:\n"
3845"1) software that runs at boot time (e.g., old versions of LILO)\n"
3846"2) booting and partitioning software from other OSs\n"
3847" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3848 cylinders);
3849}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003850#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003851
3852static void
3853read_extended(int ext) {
3854 int i;
3855 struct pte *pex;
3856 struct partition *p, *q;
3857
3858 ext_index = ext;
3859 pex = &ptes[ext];
3860 pex->ext_pointer = pex->part_table;
3861
3862 p = pex->part_table;
3863 if (!get_start_sect(p)) {
3864 fprintf(stderr,
3865 _("Bad offset in primary extended partition\n"));
3866 return;
3867 }
3868
3869 while (IS_EXTENDED (p->sys_ind)) {
3870 struct pte *pe = &ptes[partitions];
3871
3872 if (partitions >= MAXIMUM_PARTS) {
3873 /* This is not a Linux restriction, but
3874 this program uses arrays of size MAXIMUM_PARTS.
3875 Do not try to `improve' this test. */
3876 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003877#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003878 fprintf(stderr,
3879 _("Warning: deleting partitions after %d\n"),
3880 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003881 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003882#endif
3883 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003884 return;
3885 }
3886
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003887 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003888
3889 if (!extended_offset)
3890 extended_offset = get_start_sect(p);
3891
3892 q = p = pt_offset(pe->sectorbuffer, 0);
3893 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3894 if (IS_EXTENDED (p->sys_ind)) {
3895 if (pe->ext_pointer)
3896 fprintf(stderr,
3897 _("Warning: extra link "
3898 "pointer in partition table"
3899 " %d\n"), partitions + 1);
3900 else
3901 pe->ext_pointer = p;
3902 } else if (p->sys_ind) {
3903 if (pe->part_table)
3904 fprintf(stderr,
3905 _("Warning: ignoring extra "
3906 "data in partition table"
3907 " %d\n"), partitions + 1);
3908 else
3909 pe->part_table = p;
3910 }
3911 }
3912
3913 /* very strange code here... */
3914 if (!pe->part_table) {
3915 if (q != pe->ext_pointer)
3916 pe->part_table = q;
3917 else
3918 pe->part_table = q + 1;
3919 }
3920 if (!pe->ext_pointer) {
3921 if (q != pe->part_table)
3922 pe->ext_pointer = q;
3923 else
3924 pe->ext_pointer = q + 1;
3925 }
3926
3927 p = pe->ext_pointer;
3928 partitions++;
3929 }
3930
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003931#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003932 /* remove empty links */
3933 remove:
3934 for (i = 4; i < partitions; i++) {
3935 struct pte *pe = &ptes[i];
3936
3937 if (!get_nr_sects(pe->part_table) &&
3938 (partitions > 5 || ptes[4].part_table->sys_ind)) {
3939 printf("omitting empty partition (%d)\n", i+1);
3940 delete_partition(i);
3941 goto remove; /* numbering changed */
3942 }
3943 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003944#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003945}
3946
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003947#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003948static void
3949create_doslabel(void) {
3950 int i;
3951
3952 fprintf(stderr,
3953 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3954 "until you decide to write them. After that, of course, the previous\n"
3955 "content won't be recoverable.\n\n"));
3956#ifdef CONFIG_FEATURE_SUN_LABEL
3957 sun_nolabel(); /* otherwise always recognised as sun */
3958#endif
3959#ifdef CONFIG_FEATURE_SGI_LABEL
3960 sgi_nolabel(); /* otherwise always recognised as sgi */
3961#endif
3962#ifdef CONFIG_FEATURE_AIX_LABEL
3963 aix_label = 0;
3964#endif
3965#ifdef CONFIG_FEATURE_OSF_LABEL
3966 osf_label = 0;
3967 possibly_osf_label = 0;
3968#endif
3969 partitions = 4;
3970
3971 for (i = 510-64; i < 510; i++)
3972 MBRbuffer[i] = 0;
3973 write_part_table_flag(MBRbuffer);
3974 extended_offset = 0;
3975 set_all_unchanged();
3976 set_changed(0);
3977 get_boot(create_empty_dos);
3978}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003979#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003980
3981static void
3982get_sectorsize(void) {
3983 if (!user_set_sector_size &&
3984 get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
3985 int arg;
3986 if (ioctl(fd, BLKSSZGET, &arg) == 0)
3987 sector_size = arg;
3988 if (sector_size != DEFAULT_SECTOR_SIZE)
3989 printf(_("Note: sector size is %d (not %d)\n"),
3990 sector_size, DEFAULT_SECTOR_SIZE);
3991 }
3992}
3993
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003994static inline void
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003995get_kernel_geometry(void) {
3996 struct hd_geometry geometry;
3997
3998 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3999 kern_heads = geometry.heads;
4000 kern_sectors = geometry.sectors;
4001 /* never use geometry.cylinders - it is truncated */
4002 }
4003}
4004
4005static void
4006get_partition_table_geometry(void) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004007 const unsigned char *bufp = MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004008 struct partition *p;
4009 int i, h, s, hh, ss;
4010 int first = 1;
4011 int bad = 0;
4012
4013 if (!(valid_part_table_flag(bufp)))
4014 return;
4015
4016 hh = ss = 0;
4017 for (i=0; i<4; i++) {
4018 p = pt_offset(bufp, i);
4019 if (p->sys_ind != 0) {
4020 h = p->end_head + 1;
4021 s = (p->end_sector & 077);
4022 if (first) {
4023 hh = h;
4024 ss = s;
4025 first = 0;
4026 } else if (hh != h || ss != s)
4027 bad = 1;
4028 }
4029 }
4030
4031 if (!first && !bad) {
4032 pt_heads = hh;
4033 pt_sectors = ss;
4034 }
4035}
4036
4037void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004038get_geometry(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004039 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00004040 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004041
4042 get_sectorsize();
4043 sec_fac = sector_size / 512;
4044#ifdef CONFIG_FEATURE_SUN_LABEL
4045 guess_device_type();
4046#endif
4047 heads = cylinders = sectors = 0;
4048 kern_heads = kern_sectors = 0;
4049 pt_heads = pt_sectors = 0;
4050
4051 get_kernel_geometry();
4052 get_partition_table_geometry();
4053
4054 heads = user_heads ? user_heads :
4055 pt_heads ? pt_heads :
4056 kern_heads ? kern_heads : 255;
4057 sectors = user_sectors ? user_sectors :
4058 pt_sectors ? pt_sectors :
4059 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004060 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4061 /* got bytes */
4062 } else {
4063 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004064
4065 if (ioctl(fd, BLKGETSIZE, &longsectors))
4066 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004067 bytes = ((unsigned long long) longsectors) << 9;
4068 }
4069
4070 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004071
4072 sector_offset = 1;
4073 if (dos_compatible_flag)
4074 sector_offset = sectors;
4075
Eric Andersen040f4402003-07-30 08:40:37 +00004076 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004077 if (!cylinders)
4078 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004079}
4080
4081/*
4082 * Read MBR. Returns:
4083 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4084 * 0: found or created label
4085 * 1: I/O error
4086 */
4087int
4088get_boot(enum action what) {
4089 int i;
4090
4091 partitions = 4;
4092
4093 for (i = 0; i < 4; i++) {
4094 struct pte *pe = &ptes[i];
4095
4096 pe->part_table = pt_offset(MBRbuffer, i);
4097 pe->ext_pointer = NULL;
4098 pe->offset = 0;
4099 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004100#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004101 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004102#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004103 }
4104
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004105#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004106 if (what == create_empty_sun && check_sun_label())
4107 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004108#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004109
4110 memset(MBRbuffer, 0, 512);
4111
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004112#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004113 if (what == create_empty_dos)
4114 goto got_dos_table; /* skip reading disk */
4115
4116 if ((fd = open(disk_device, type_open)) < 0) {
4117 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4118 if (what == try_only)
4119 return 1;
4120 fdisk_fatal(unable_to_open);
4121 } else
4122 printf(_("You will not be able to write "
4123 "the partition table.\n"));
4124 }
4125
4126 if (512 != read(fd, MBRbuffer, 512)) {
4127 if (what == try_only)
4128 return 1;
4129 fdisk_fatal(unable_to_read);
4130 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004131#else
4132 if ((fd = open(disk_device, O_RDONLY)) < 0)
4133 return 1;
4134 if (512 != read(fd, MBRbuffer, 512))
4135 return 1;
4136#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004137
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004138 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004139
4140 update_units();
4141
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004142#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004143 if (check_sun_label())
4144 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004145#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004146
4147#ifdef CONFIG_FEATURE_SGI_LABEL
4148 if (check_sgi_label())
4149 return 0;
4150#endif
4151
4152#ifdef CONFIG_FEATURE_AIX_LABEL
4153 if (check_aix_label())
4154 return 0;
4155#endif
4156
4157#ifdef CONFIG_FEATURE_OSF_LABEL
4158 if (check_osf_label()) {
4159 possibly_osf_label = 1;
4160 if (!valid_part_table_flag(MBRbuffer)) {
4161 osf_label = 1;
4162 return 0;
4163 }
4164 printf(_("This disk has both DOS and BSD magic.\n"
4165 "Give the 'b' command to go to BSD mode.\n"));
4166 }
4167#endif
4168
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004169#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004170got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004171#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004172
4173 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004174#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4175 return -1;
4176#else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004177 switch(what) {
4178 case fdisk:
4179 fprintf(stderr,
4180 _("Device contains neither a valid DOS "
4181 "partition table, nor Sun, SGI or OSF "
4182 "disklabel\n"));
4183#ifdef __sparc__
4184#ifdef CONFIG_FEATURE_SUN_LABEL
4185 create_sunlabel();
4186#endif
4187#else
4188 create_doslabel();
4189#endif
4190 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004191 case try_only:
4192 return -1;
4193 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004194#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004195 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004196#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004197 break;
4198 default:
4199 fprintf(stderr, _("Internal error\n"));
4200 exit(1);
4201 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004202#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004203 }
4204
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004205#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004206 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004207#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004208 warn_geometry();
4209
4210 for (i = 0; i < 4; i++) {
4211 struct pte *pe = &ptes[i];
4212
4213 if (IS_EXTENDED (pe->part_table->sys_ind)) {
4214 if (partitions != 4)
4215 fprintf(stderr, _("Ignoring extra extended "
4216 "partition %d\n"), i + 1);
4217 else
4218 read_extended(i);
4219 }
4220 }
4221
4222 for (i = 3; i < partitions; i++) {
4223 struct pte *pe = &ptes[i];
4224
4225 if (!valid_part_table_flag(pe->sectorbuffer)) {
4226 fprintf(stderr,
4227 _("Warning: invalid flag 0x%04x of partition "
4228 "table %d will be corrected by w(rite)\n"),
4229 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004230#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004231 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004232#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004233 }
4234 }
4235
4236 return 0;
4237}
4238
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004239#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004240/*
4241 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4242 * If the user hits Enter, DFLT is returned.
4243 * Answers like +10 are interpreted as offsets from BASE.
4244 *
4245 * There is no default if DFLT is not between LOW and HIGH.
4246 */
4247static uint
4248read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4249{
4250 uint i;
4251 int default_ok = 1;
4252 static char *ms = NULL;
4253 static int mslen = 0;
4254
4255 if (!ms || strlen(mesg)+100 > mslen) {
4256 mslen = strlen(mesg)+200;
4257 ms = xrealloc(ms,mslen);
4258 }
4259
4260 if (dflt < low || dflt > high)
4261 default_ok = 0;
4262
4263 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004264 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004265 mesg, low, high, dflt);
4266 else
Eric Andersen040f4402003-07-30 08:40:37 +00004267 snprintf(ms, mslen, "%s (%u-%u): ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004268 mesg, low, high);
4269
4270 while (1) {
4271 int use_default = default_ok;
4272
4273 /* ask question and read answer */
4274 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4275 && *line_ptr != '-' && *line_ptr != '+')
4276 continue;
4277
Eric Andersenc48d49a2003-07-03 10:02:32 +00004278 if (*line_ptr == '+' || *line_ptr == '-') {
4279 int minus = (*line_ptr == '-');
4280 int absolute = 0;
4281
4282 i = atoi(line_ptr+1);
4283
4284 while (isdigit(*++line_ptr))
4285 use_default = 0;
4286
4287 switch (*line_ptr) {
4288 case 'c':
4289 case 'C':
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004290 if (!display_in_cyl_units)
4291 i *= heads * sectors;
4292 break;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004293 case 'K':
Eric Andersen040f4402003-07-30 08:40:37 +00004294 absolute = 1024;
4295 break;
4296 case 'k':
Eric Andersenc48d49a2003-07-03 10:02:32 +00004297 absolute = 1000;
4298 break;
4299 case 'm':
4300 case 'M':
4301 absolute = 1000000;
4302 break;
4303 case 'g':
4304 case 'G':
4305 absolute = 1000000000;
4306 break;
4307 default:
4308 break;
4309 }
4310 if (absolute) {
4311 unsigned long long bytes;
4312 unsigned long unit;
4313
4314 bytes = (unsigned long long) i * absolute;
4315 unit = sector_size * units_per_sector;
4316 bytes += unit/2; /* round */
4317 bytes /= unit;
4318 i = bytes;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004319 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00004320 if (minus)
4321 i = -i;
4322 i += base;
4323 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004324 i = atoi(line_ptr);
4325 while (isdigit(*line_ptr)) {
4326 line_ptr++;
4327 use_default = 0;
4328 }
4329 }
4330 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004331 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004332 if (i >= low && i <= high)
4333 break;
4334 else
4335 printf(_("Value out of range.\n"));
4336 }
4337 return i;
4338}
4339
4340int
4341get_partition(int warn, int max) {
4342 struct pte *pe;
4343 int i;
4344
4345 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4346 pe = &ptes[i];
4347
4348 if (warn) {
4349 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4350#ifdef CONFIG_FEATURE_SUN_LABEL
4351 || (sun_label &&
4352 (!sunlabel->partitions[i].num_sectors ||
4353 !sunlabel->infos[i].id))
4354#endif
4355#ifdef CONFIG_FEATURE_SGI_LABEL
4356 || (sgi_label && (!sgi_get_num_sectors(i)))
4357#endif
4358 )
4359 fprintf(stderr,
4360 _("Warning: partition %d has empty type\n"),
4361 i+1);
4362 }
4363 return i;
4364}
4365
4366static int
4367get_existing_partition(int warn, int max) {
4368 int pno = -1;
4369 int i;
4370
4371 for (i = 0; i < max; i++) {
4372 struct pte *pe = &ptes[i];
4373 struct partition *p = pe->part_table;
4374
4375 if (p && !is_cleared_partition(p)) {
4376 if (pno >= 0)
4377 goto not_unique;
4378 pno = i;
4379 }
4380 }
4381 if (pno >= 0) {
4382 printf(_("Selected partition %d\n"), pno+1);
4383 return pno;
4384 }
4385 printf(_("No partition is defined yet!\n"));
4386 return -1;
4387
4388 not_unique:
4389 return get_partition(warn, max);
4390}
4391
4392static int
4393get_nonexisting_partition(int warn, int max) {
4394 int pno = -1;
4395 int i;
4396
4397 for (i = 0; i < max; i++) {
4398 struct pte *pe = &ptes[i];
4399 struct partition *p = pe->part_table;
4400
4401 if (p && is_cleared_partition(p)) {
4402 if (pno >= 0)
4403 goto not_unique;
4404 pno = i;
4405 }
4406 }
4407 if (pno >= 0) {
4408 printf(_("Selected partition %d\n"), pno+1);
4409 return pno;
4410 }
4411 printf(_("All primary partitions have been defined already!\n"));
4412 return -1;
4413
4414 not_unique:
4415 return get_partition(warn, max);
4416}
4417
4418
4419void change_units(void)
4420{
4421 display_in_cyl_units = !display_in_cyl_units;
4422 update_units();
4423 printf(_("Changing display/entry units to %s\n"),
4424 str_units(PLURAL));
4425}
4426
4427static void
4428toggle_active(int i) {
4429 struct pte *pe = &ptes[i];
4430 struct partition *p = pe->part_table;
4431
4432 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
4433 fprintf(stderr,
4434 _("WARNING: Partition %d is an extended partition\n"),
4435 i + 1);
4436 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4437 pe->changed = 1;
4438}
4439
4440static void
4441toggle_dos_compatibility_flag(void) {
4442 dos_compatible_flag = ~dos_compatible_flag;
4443 if (dos_compatible_flag) {
4444 sector_offset = sectors;
4445 printf(_("DOS Compatibility flag is set\n"));
4446 }
4447 else {
4448 sector_offset = 1;
4449 printf(_("DOS Compatibility flag is not set\n"));
4450 }
4451}
4452
4453static void
4454delete_partition(int i) {
4455 struct pte *pe = &ptes[i];
4456 struct partition *p = pe->part_table;
4457 struct partition *q = pe->ext_pointer;
4458
4459/* Note that for the fifth partition (i == 4) we don't actually
4460 * decrement partitions.
4461 */
4462
4463 if (warn_geometry())
4464 return; /* C/H/S not set */
4465 pe->changed = 1;
4466
4467#ifdef CONFIG_FEATURE_SUN_LABEL
4468 if (sun_label) {
4469 sun_delete_partition(i);
4470 return;
4471 }
4472#endif
4473#ifdef CONFIG_FEATURE_SGI_LABEL
4474 if (sgi_label) {
4475 sgi_delete_partition(i);
4476 return;
4477 }
4478#endif
4479
4480 if (i < 4) {
4481 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
4482 partitions = 4;
4483 ptes[ext_index].ext_pointer = NULL;
4484 extended_offset = 0;
4485 }
4486 clear_partition(p);
4487 return;
4488 }
4489
4490 if (!q->sys_ind && i > 4) {
4491 /* the last one in the chain - just delete */
4492 --partitions;
4493 --i;
4494 clear_partition(ptes[i].ext_pointer);
4495 ptes[i].changed = 1;
4496 } else {
4497 /* not the last one - further ones will be moved down */
4498 if (i > 4) {
4499 /* delete this link in the chain */
4500 p = ptes[i-1].ext_pointer;
4501 *p = *q;
4502 set_start_sect(p, get_start_sect(q));
4503 set_nr_sects(p, get_nr_sects(q));
4504 ptes[i-1].changed = 1;
4505 } else if (partitions > 5) { /* 5 will be moved to 4 */
4506 /* the first logical in a longer chain */
4507 pe = &ptes[5];
4508
4509 if (pe->part_table) /* prevent SEGFAULT */
4510 set_start_sect(pe->part_table,
4511 get_partition_start(pe) -
4512 extended_offset);
4513 pe->offset = extended_offset;
4514 pe->changed = 1;
4515 }
4516
4517 if (partitions > 5) {
4518 partitions--;
4519 while (i < partitions) {
4520 ptes[i] = ptes[i+1];
4521 i++;
4522 }
4523 } else
4524 /* the only logical: clear only */
4525 clear_partition(ptes[i].part_table);
4526 }
4527}
4528
4529static void
4530change_sysid(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004531 int i, sys, origsys;
4532 struct partition *p;
4533
Eric Andersen040f4402003-07-30 08:40:37 +00004534#ifdef CONFIG_FEATURE_SGI_LABEL
4535 /* If sgi_label then don't use get_existing_partition,
4536 let the user select a partition, since get_existing_partition()
4537 only works for Linux like partition tables. */
4538 if (!sgi_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004539 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004540 } else {
4541 i = get_partition(0, partitions);
4542 }
4543#else
4544 i = get_existing_partition(0, partitions);
4545#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004546 if (i == -1)
4547 return;
4548 p = ptes[i].part_table;
4549 origsys = sys = get_sysid(i);
4550
4551 /* if changing types T to 0 is allowed, then
4552 the reverse change must be allowed, too */
4553 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4554 printf(_("Partition %d does not exist yet!\n"), i + 1);
4555 else while (1) {
4556 sys = read_hex (get_sys_types());
4557
4558 if (!sys && !sgi_label && !sun_label) {
4559 printf(_("Type 0 means free space to many systems\n"
4560 "(but not to Linux). Having partitions of\n"
4561 "type 0 is probably unwise. You can delete\n"
4562 "a partition using the `d' command.\n"));
4563 /* break; */
4564 }
4565
4566 if (!sun_label && !sgi_label) {
4567 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
4568 printf(_("You cannot change a partition into"
4569 " an extended one or vice versa\n"
4570 "Delete it first.\n"));
4571 break;
4572 }
4573 }
4574
4575 if (sys < 256) {
4576#ifdef CONFIG_FEATURE_SUN_LABEL
4577 if (sun_label && i == 2 && sys != WHOLE_DISK)
4578 printf(_("Consider leaving partition 3 "
4579 "as Whole disk (5),\n"
4580 "as SunOS/Solaris expects it and "
4581 "even Linux likes it.\n\n"));
4582#endif
4583#ifdef CONFIG_FEATURE_SGI_LABEL
4584 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4585 || (i == 8 && sys != 0)))
4586 printf(_("Consider leaving partition 9 "
4587 "as volume header (0),\nand "
4588 "partition 11 as entire volume (6)"
4589 "as IRIX expects it.\n\n"));
4590#endif
4591 if (sys == origsys)
4592 break;
4593#ifdef CONFIG_FEATURE_SUN_LABEL
4594 if (sun_label) {
4595 sun_change_sysid(i, sys);
4596 } else
4597#endif
4598#ifdef CONFIG_FEATURE_SGI_LABEL
4599 if (sgi_label) {
4600 sgi_change_sysid(i, sys);
4601 } else
4602#endif
4603 p->sys_ind = sys;
4604 printf (_("Changed system type of partition %d "
4605 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004606 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004607 ptes[i].changed = 1;
4608 if (is_dos_partition(origsys) ||
4609 is_dos_partition(sys))
4610 dos_changed = 1;
4611 break;
4612 }
4613 }
4614}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004615#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4616
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004617
4618/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4619 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4620 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4621 * Lubkin Oct. 1991). */
4622
4623static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
4624 int spc = heads * sectors;
4625
4626 *c = ls / spc;
4627 ls = ls % spc;
4628 *h = ls / sectors;
4629 *s = ls % sectors + 1; /* sectors count from 1 */
4630}
4631
4632static void check_consistency(const struct partition *p, int partition) {
4633 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4634 uint pec, peh, pes; /* physical ending c, h, s */
4635 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4636 uint lec, leh, les; /* logical ending c, h, s */
4637
4638 if (!heads || !sectors || (partition >= 4))
4639 return; /* do not check extended partitions */
4640
4641/* physical beginning c, h, s */
4642 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4643 pbh = p->head;
4644 pbs = p->sector & 0x3f;
4645
4646/* physical ending c, h, s */
4647 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4648 peh = p->end_head;
4649 pes = p->end_sector & 0x3f;
4650
4651/* compute logical beginning (c, h, s) */
4652 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4653
4654/* compute logical ending (c, h, s) */
4655 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4656
4657/* Same physical / logical beginning? */
4658 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4659 printf(_("Partition %d has different physical/logical "
4660 "beginnings (non-Linux?):\n"), partition + 1);
4661 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4662 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4663 }
4664
4665/* Same physical / logical ending? */
4666 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4667 printf(_("Partition %d has different physical/logical "
4668 "endings:\n"), partition + 1);
4669 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4670 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4671 }
4672
4673#if 0
4674/* Beginning on cylinder boundary? */
4675 if (pbh != !pbc || pbs != 1) {
4676 printf(_("Partition %i does not start on cylinder "
4677 "boundary:\n"), partition + 1);
4678 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4679 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4680 }
4681#endif
4682
4683/* Ending on cylinder boundary? */
4684 if (peh != (heads - 1) || pes != sectors) {
Eric Andersenc48d49a2003-07-03 10:02:32 +00004685 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004686 partition + 1);
4687#if 0
4688 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4689 printf(_("should be (%d, %d, %d)\n"),
4690 pec, heads - 1, sectors);
4691#endif
4692 }
4693}
4694
4695static void
4696list_disk_geometry(void) {
Eric Andersen040f4402003-07-30 08:40:37 +00004697 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004698 long megabytes = bytes/1000000;
4699
4700 if (megabytes < 10000)
4701 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4702 disk_device, megabytes, bytes);
4703 else
4704 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4705 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4706 printf(_("%d heads, %d sectors/track, %d cylinders"),
4707 heads, sectors, cylinders);
4708 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004709 printf(_(", total %llu sectors"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004710 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004711 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004712 str_units(PLURAL),
4713 units_per_sector, sector_size, units_per_sector * sector_size);
4714}
4715
4716/*
4717 * Check whether partition entries are ordered by their starting positions.
4718 * Return 0 if OK. Return i if partition i should have been earlier.
4719 * Two separate checks: primary and logical partitions.
4720 */
4721static int
4722wrong_p_order(int *prev) {
4723 const struct pte *pe;
4724 const struct partition *p;
4725 uint last_p_start_pos = 0, p_start_pos;
4726 int i, last_i = 0;
4727
4728 for (i = 0 ; i < partitions; i++) {
4729 if (i == 4) {
4730 last_i = 4;
4731 last_p_start_pos = 0;
4732 }
4733 pe = &ptes[i];
4734 if ((p = pe->part_table)->sys_ind) {
4735 p_start_pos = get_partition_start(pe);
4736
4737 if (last_p_start_pos > p_start_pos) {
4738 if (prev)
4739 *prev = last_i;
4740 return i;
4741 }
4742
4743 last_p_start_pos = p_start_pos;
4744 last_i = i;
4745 }
4746 }
4747 return 0;
4748}
4749
4750#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4751/*
4752 * Fix the chain of logicals.
4753 * extended_offset is unchanged, the set of sectors used is unchanged
4754 * The chain is sorted so that sectors increase, and so that
4755 * starting sectors increase.
4756 *
4757 * After this it may still be that cfdisk doesnt like the table.
4758 * (This is because cfdisk considers expanded parts, from link to
4759 * end of partition, and these may still overlap.)
4760 * Now
4761 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4762 * may help.
4763 */
4764static void
4765fix_chain_of_logicals(void) {
4766 int j, oj, ojj, sj, sjj;
4767 struct partition *pj,*pjj,tmp;
4768
4769 /* Stage 1: sort sectors but leave sector of part 4 */
4770 /* (Its sector is the global extended_offset.) */
4771 stage1:
4772 for (j = 5; j < partitions-1; j++) {
4773 oj = ptes[j].offset;
4774 ojj = ptes[j+1].offset;
4775 if (oj > ojj) {
4776 ptes[j].offset = ojj;
4777 ptes[j+1].offset = oj;
4778 pj = ptes[j].part_table;
4779 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4780 pjj = ptes[j+1].part_table;
4781 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4782 set_start_sect(ptes[j-1].ext_pointer,
4783 ojj-extended_offset);
4784 set_start_sect(ptes[j].ext_pointer,
4785 oj-extended_offset);
4786 goto stage1;
4787 }
4788 }
4789
4790 /* Stage 2: sort starting sectors */
4791 stage2:
4792 for (j = 4; j < partitions-1; j++) {
4793 pj = ptes[j].part_table;
4794 pjj = ptes[j+1].part_table;
4795 sj = get_start_sect(pj);
4796 sjj = get_start_sect(pjj);
4797 oj = ptes[j].offset;
4798 ojj = ptes[j+1].offset;
4799 if (oj+sj > ojj+sjj) {
4800 tmp = *pj;
4801 *pj = *pjj;
4802 *pjj = tmp;
4803 set_start_sect(pj, ojj+sjj-oj);
4804 set_start_sect(pjj, oj+sj-ojj);
4805 goto stage2;
4806 }
4807 }
4808
4809 /* Probably something was changed */
4810 for (j = 4; j < partitions; j++)
4811 ptes[j].changed = 1;
4812}
4813
4814
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004815static void
4816fix_partition_table_order(void) {
4817 struct pte *pei, *pek;
4818 int i,k;
4819
4820 if (!wrong_p_order(NULL)) {
4821 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4822 return;
4823 }
4824
4825 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4826 /* partition i should have come earlier, move it */
4827 /* We have to move data in the MBR */
4828 struct partition *pi, *pk, *pe, pbuf;
4829 pei = &ptes[i];
4830 pek = &ptes[k];
4831
4832 pe = pei->ext_pointer;
4833 pei->ext_pointer = pek->ext_pointer;
4834 pek->ext_pointer = pe;
4835
4836 pi = pei->part_table;
4837 pk = pek->part_table;
4838
4839 memmove(&pbuf, pi, sizeof(struct partition));
4840 memmove(pi, pk, sizeof(struct partition));
4841 memmove(pk, &pbuf, sizeof(struct partition));
4842
4843 pei->changed = pek->changed = 1;
4844 }
4845
4846 if (i)
4847 fix_chain_of_logicals();
4848
4849 printf("Done.\n");
4850
4851}
4852#endif
4853
4854static void
4855list_table(int xtra) {
4856 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004857 int i, w;
4858
4859#ifdef CONFIG_FEATURE_SUN_LABEL
4860 if (sun_label) {
4861 sun_list_table(xtra);
4862 return;
4863 }
4864#endif
4865
4866#ifdef CONFIG_FEATURE_SGI_LABEL
4867 if (sgi_label) {
4868 sgi_list_table(xtra);
4869 return;
4870 }
4871#endif
4872
4873 list_disk_geometry();
4874
4875#ifdef CONFIG_FEATURE_OSF_LABEL
4876 if (osf_label) {
4877 xbsd_print_disklabel(xtra);
4878 return;
4879 }
4880#endif
4881
4882 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4883 but if the device name ends in a digit, say /dev/foo1,
4884 then the partition is called /dev/foo1p3. */
4885 w = strlen(disk_device);
4886 if (w && isdigit(disk_device[w-1]))
4887 w++;
4888 if (w < 5)
4889 w = 5;
4890
4891 printf(_("%*s Boot Start End Blocks Id System\n"),
4892 w+1, _("Device"));
4893
4894 for (i = 0; i < partitions; i++) {
4895 const struct pte *pe = &ptes[i];
4896
4897 p = pe->part_table;
4898 if (p && !is_cleared_partition(p)) {
4899 unsigned int psects = get_nr_sects(p);
4900 unsigned int pblocks = psects;
4901 unsigned int podd = 0;
4902
4903 if (sector_size < 1024) {
4904 pblocks /= (1024 / sector_size);
4905 podd = psects % (1024 / sector_size);
4906 }
4907 if (sector_size > 1024)
4908 pblocks *= (sector_size / 1024);
4909 printf(
Eric Andersen040f4402003-07-30 08:40:37 +00004910 "%s %c %11lu %11lu %11lu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004911 partname(disk_device, i+1, w+2),
4912/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4913 ? '*' : '?',
Eric Andersen040f4402003-07-30 08:40:37 +00004914/* start */ (unsigned long) cround(get_partition_start(pe)),
4915/* end */ (unsigned long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004916 - (psects ? 1 : 0)),
Eric Andersen040f4402003-07-30 08:40:37 +00004917/* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004918/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004919/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004920 check_consistency(p, i);
4921 }
4922 }
4923
4924 /* Is partition table in disk order? It need not be, but... */
4925 /* partition table entries are not checked for correct order if this
4926 is a sgi, sun or aix labeled disk... */
4927 if (dos_label && wrong_p_order(NULL)) {
4928 printf(_("\nPartition table entries are not in disk order\n"));
4929 }
4930}
4931
4932#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4933static void
4934x_list_table(int extend) {
4935 const struct pte *pe;
4936 const struct partition *p;
4937 int i;
4938
4939 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4940 disk_device, heads, sectors, cylinders);
4941 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4942 for (i = 0 ; i < partitions; i++) {
4943 pe = &ptes[i];
4944 p = (extend ? pe->ext_pointer : pe->part_table);
4945 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004946 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004947 i + 1, p->boot_ind, p->head,
4948 sector(p->sector),
4949 cylinder(p->sector, p->cyl), p->end_head,
4950 sector(p->end_sector),
4951 cylinder(p->end_sector, p->end_cyl),
4952 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4953 if (p->sys_ind)
4954 check_consistency(p, i);
4955 }
4956 }
4957}
4958#endif
4959
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004960#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004961static void
4962fill_bounds(uint *first, uint *last) {
4963 int i;
4964 const struct pte *pe = &ptes[0];
4965 const struct partition *p;
4966
4967 for (i = 0; i < partitions; pe++,i++) {
4968 p = pe->part_table;
4969 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
4970 first[i] = 0xffffffff;
4971 last[i] = 0;
4972 } else {
4973 first[i] = get_partition_start(pe);
4974 last[i] = first[i] + get_nr_sects(p) - 1;
4975 }
4976 }
4977}
4978
4979static void
4980check(int n, uint h, uint s, uint c, uint start) {
4981 uint total, real_s, real_c;
4982
4983 real_s = sector(s) - 1;
4984 real_c = cylinder(s, c);
4985 total = (real_c * sectors + real_s) * heads + h;
4986 if (!total)
4987 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
4988 if (h >= heads)
4989 fprintf(stderr,
4990 _("Partition %d: head %d greater than maximum %d\n"),
4991 n, h + 1, heads);
4992 if (real_s >= sectors)
4993 fprintf(stderr, _("Partition %d: sector %d greater than "
4994 "maximum %d\n"), n, s, sectors);
4995 if (real_c >= cylinders)
4996 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
4997 "maximum %d\n"), n, real_c + 1, cylinders);
4998 if (cylinders <= 1024 && start != total)
4999 fprintf(stderr,
5000 _("Partition %d: previous sectors %d disagrees with "
5001 "total %d\n"), n, start, total);
5002}
5003
5004static void
5005verify(void) {
5006 int i, j;
5007 uint total = 1;
5008 uint first[partitions], last[partitions];
5009 struct partition *p;
5010
5011 if (warn_geometry())
5012 return;
5013
5014#ifdef CONFIG_FEATURE_SUN_LABEL
5015 if (sun_label) {
5016 verify_sun();
5017 return;
5018 }
5019#endif
5020#ifdef CONFIG_FEATURE_SGI_LABEL
5021 if (sgi_label) {
5022 verify_sgi(1);
5023 return;
5024 }
5025#endif
5026
5027 fill_bounds(first, last);
5028 for (i = 0; i < partitions; i++) {
5029 struct pte *pe = &ptes[i];
5030
5031 p = pe->part_table;
5032 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
5033 check_consistency(p, i);
5034 if (get_partition_start(pe) < first[i])
5035 printf(_("Warning: bad start-of-data in "
5036 "partition %d\n"), i + 1);
5037 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5038 last[i]);
5039 total += last[i] + 1 - first[i];
5040 for (j = 0; j < i; j++)
5041 if ((first[i] >= first[j] && first[i] <= last[j])
5042 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5043 printf(_("Warning: partition %d overlaps "
5044 "partition %d.\n"), j + 1, i + 1);
5045 total += first[i] >= first[j] ?
5046 first[i] : first[j];
5047 total -= last[i] <= last[j] ?
5048 last[i] : last[j];
5049 }
5050 }
5051 }
5052
5053 if (extended_offset) {
5054 struct pte *pex = &ptes[ext_index];
5055 uint e_last = get_start_sect(pex->part_table) +
5056 get_nr_sects(pex->part_table) - 1;
5057
5058 for (i = 4; i < partitions; i++) {
5059 total++;
5060 p = ptes[i].part_table;
5061 if (!p->sys_ind) {
5062 if (i != 4 || i + 1 < partitions)
5063 printf(_("Warning: partition %d "
5064 "is empty\n"), i + 1);
5065 }
5066 else if (first[i] < extended_offset ||
5067 last[i] > e_last)
5068 printf(_("Logical partition %d not entirely in "
5069 "partition %d\n"), i + 1, ext_index + 1);
5070 }
5071 }
5072
5073 if (total > heads * sectors * cylinders)
5074 printf(_("Total allocated sectors %d greater than the maximum "
5075 "%d\n"), total, heads * sectors * cylinders);
5076 else if ((total = heads * sectors * cylinders - total) != 0)
5077 printf(_("%d unallocated sectors\n"), total);
5078}
5079
5080static void
5081add_partition(int n, int sys) {
5082 char mesg[256]; /* 48 does not suffice in Japanese */
5083 int i, readed = 0;
5084 struct partition *p = ptes[n].part_table;
5085 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005086 long long llimit;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005087 uint start, stop = 0, limit, temp,
5088 first[partitions], last[partitions];
5089
5090 if (p && p->sys_ind) {
5091 printf(_("Partition %d is already defined. Delete "
5092 "it before re-adding it.\n"), n + 1);
5093 return;
5094 }
5095 fill_bounds(first, last);
5096 if (n < 4) {
5097 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005098 if (display_in_cyl_units || !total_number_of_sectors)
5099 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005100 else
Eric Andersen040f4402003-07-30 08:40:37 +00005101 llimit = total_number_of_sectors - 1;
5102 limit = llimit;
5103 if (limit != llimit)
5104 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005105 if (extended_offset) {
5106 first[ext_index] = extended_offset;
5107 last[ext_index] = get_start_sect(q) +
5108 get_nr_sects(q) - 1;
5109 }
5110 } else {
5111 start = extended_offset + sector_offset;
5112 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5113 }
5114 if (display_in_cyl_units)
5115 for (i = 0; i < partitions; i++)
5116 first[i] = (cround(first[i]) - 1) * units_per_sector;
5117
5118 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5119 do {
5120 temp = start;
5121 for (i = 0; i < partitions; i++) {
5122 int lastplusoff;
5123
5124 if (start == ptes[i].offset)
5125 start += sector_offset;
5126 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
5127 if (start >= first[i] && start <= lastplusoff)
5128 start = lastplusoff + 1;
5129 }
5130 if (start > limit)
5131 break;
5132 if (start >= temp+units_per_sector && readed) {
5133 printf(_("Sector %d is already allocated\n"), temp);
5134 temp = start;
5135 readed = 0;
5136 }
5137 if (!readed && start == temp) {
5138 uint saved_start;
5139
5140 saved_start = start;
5141 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5142 0, mesg);
5143 if (display_in_cyl_units) {
5144 start = (start - 1) * units_per_sector;
5145 if (start < saved_start) start = saved_start;
5146 }
5147 readed = 1;
5148 }
5149 } while (start != temp || !readed);
5150 if (n > 4) { /* NOT for fifth partition */
5151 struct pte *pe = &ptes[n];
5152
5153 pe->offset = start - sector_offset;
5154 if (pe->offset == extended_offset) { /* must be corrected */
5155 pe->offset++;
5156 if (sector_offset == 1)
5157 start++;
5158 }
5159 }
5160
5161 for (i = 0; i < partitions; i++) {
5162 struct pte *pe = &ptes[i];
5163
5164 if (start < pe->offset && limit >= pe->offset)
5165 limit = pe->offset - 1;
5166 if (start < first[i] && limit >= first[i])
5167 limit = first[i] - 1;
5168 }
5169 if (start > limit) {
5170 printf(_("No free sectors available\n"));
5171 if (n > 4)
5172 partitions--;
5173 return;
5174 }
5175 if (cround(start) == cround(limit)) {
5176 stop = limit;
5177 } else {
5178 snprintf(mesg, sizeof(mesg),
5179 _("Last %s or +size or +sizeM or +sizeK"),
5180 str_units(SINGULAR));
5181 stop = read_int(cround(start), cround(limit), cround(limit),
5182 cround(start), mesg);
5183 if (display_in_cyl_units) {
5184 stop = stop * units_per_sector - 1;
5185 if (stop >limit)
5186 stop = limit;
5187 }
5188 }
5189
5190 set_partition(n, 0, start, stop, sys);
5191 if (n > 4)
5192 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5193
5194 if (IS_EXTENDED (sys)) {
5195 struct pte *pe4 = &ptes[4];
5196 struct pte *pen = &ptes[n];
5197
5198 ext_index = n;
5199 pen->ext_pointer = p;
5200 pe4->offset = extended_offset = start;
5201 pe4->sectorbuffer = xcalloc(1, sector_size);
5202 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5203 pe4->ext_pointer = pe4->part_table + 1;
5204 pe4->changed = 1;
5205 partitions = 5;
5206 }
5207}
5208
5209static void
5210add_logical(void) {
5211 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5212 struct pte *pe = &ptes[partitions];
5213
5214 pe->sectorbuffer = xcalloc(1, sector_size);
5215 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5216 pe->ext_pointer = pe->part_table + 1;
5217 pe->offset = 0;
5218 pe->changed = 1;
5219 partitions++;
5220 }
5221 add_partition(partitions - 1, LINUX_NATIVE);
5222}
5223
5224static void
5225new_partition(void) {
5226 int i, free_primary = 0;
5227
5228 if (warn_geometry())
5229 return;
5230
5231#ifdef CONFIG_FEATURE_SUN_LABEL
5232 if (sun_label) {
5233 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5234 return;
5235 }
5236#endif
5237#ifdef CONFIG_FEATURE_SGI_LABEL
5238 if (sgi_label) {
5239 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5240 return;
5241 }
5242#endif
5243#ifdef CONFIG_FEATURE_AIX_LABEL
5244 if (aix_label) {
5245 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5246 "\n\tIf you want to add DOS-type partitions, create"
5247 "\n\ta new empty DOS partition table first. (Use o.)"
5248 "\n\tWARNING: "
5249 "This will destroy the present disk contents.\n"));
5250 return;
5251 }
5252#endif
5253
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005254 for (i = 0; i < 4; i++)
5255 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005256
5257 if (!free_primary && partitions >= MAXIMUM_PARTS) {
5258 printf(_("The maximum number of partitions has been created\n"));
5259 return;
5260 }
5261
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005262 if (!free_primary) {
5263 if (extended_offset)
5264 add_logical();
5265 else
5266 printf(_("You must delete some partition and add "
5267 "an extended partition first\n"));
5268 } else {
5269 char c, line[LINE_LENGTH];
5270 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5271 "partition (1-4)\n",
5272 "Command action", (extended_offset ?
5273 "l logical (5 or over)" : "e extended"));
5274 while (1) {
5275 if ((c = read_char(line)) == 'p' || c == 'P') {
5276 i = get_nonexisting_partition(0, 4);
5277 if (i >= 0)
5278 add_partition(i, LINUX_NATIVE);
5279 return;
5280 }
5281 else if (c == 'l' && extended_offset) {
5282 add_logical();
5283 return;
5284 }
5285 else if (c == 'e' && !extended_offset) {
5286 i = get_nonexisting_partition(0, 4);
5287 if (i >= 0)
5288 add_partition(i, EXTENDED);
5289 return;
5290 }
5291 else
5292 printf(_("Invalid partition number "
5293 "for type `%c'\n"), c);
5294 }
5295 }
5296}
5297
5298static void
5299write_table(void) {
5300 int i;
5301
5302 if (dos_label) {
5303 for (i=0; i<3; i++)
5304 if (ptes[i].changed)
5305 ptes[3].changed = 1;
5306 for (i = 3; i < partitions; i++) {
5307 struct pte *pe = &ptes[i];
5308
5309 if (pe->changed) {
5310 write_part_table_flag(pe->sectorbuffer);
5311 write_sector(pe->offset, pe->sectorbuffer);
5312 }
5313 }
5314 }
5315#ifdef CONFIG_FEATURE_SGI_LABEL
5316 else if (sgi_label) {
5317 /* no test on change? the printf below might be mistaken */
5318 sgi_write_table();
5319 }
5320#endif
5321#ifdef CONFIG_FEATURE_SUN_LABEL
5322 else if (sun_label) {
5323 int needw = 0;
5324
5325 for (i=0; i<8; i++)
5326 if (ptes[i].changed)
5327 needw = 1;
5328 if (needw)
5329 sun_write_table();
5330 }
5331#endif
5332
5333 printf(_("The partition table has been altered!\n\n"));
5334 reread_partition_table(1);
5335}
5336
5337void
5338reread_partition_table(int leave) {
5339 int error = 0;
5340 int i;
5341
5342 printf(_("Calling ioctl() to re-read partition table.\n"));
5343 sync();
5344 sleep(2);
5345 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5346 error = errno;
5347 } else {
5348 /* some kernel versions (1.2.x) seem to have trouble
5349 rereading the partition table, but if asked to do it
5350 twice, the second time works. - biro@yggdrasil.com */
5351 sync();
5352 sleep(2);
5353 if ((i = ioctl(fd, BLKRRPART)) != 0)
5354 error = errno;
5355 }
5356
5357 if (i) {
5358 printf(_("\nWARNING: Re-reading the partition table "
5359 "failed with error %d: %s.\n"
5360 "The kernel still uses the old table.\n"
5361 "The new table will be used "
5362 "at the next reboot.\n"),
5363 error, strerror(error));
5364 }
5365
5366 if (dos_changed)
5367 printf(
5368 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5369 "partitions, please see the fdisk manual page for additional\n"
5370 "information.\n"));
5371
5372 if (leave) {
5373 close(fd);
5374
5375 printf(_("Syncing disks.\n"));
5376 sync();
5377 sleep(4); /* for sync() */
5378 exit(!!i);
5379 }
5380}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005381#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005382
5383#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5384#define MAX_PER_LINE 16
5385static void
5386print_buffer(char pbuffer[]) {
5387 int i,
5388 l;
5389
5390 for (i = 0, l = 0; i < sector_size; i++, l++) {
5391 if (l == 0)
5392 printf("0x%03X:", i);
5393 printf(" %02X", (unsigned char) pbuffer[i]);
5394 if (l == MAX_PER_LINE - 1) {
5395 printf("\n");
5396 l = -1;
5397 }
5398 }
5399 if (l > 0)
5400 printf("\n");
5401 printf("\n");
5402}
5403
5404
5405static void
5406print_raw(void) {
5407 int i;
5408
5409 printf(_("Device: %s\n"), disk_device);
5410#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5411 if (sun_label || sgi_label)
5412 print_buffer(MBRbuffer);
5413 else
5414#endif
5415 for (i = 3; i < partitions; i++)
5416 print_buffer(ptes[i].sectorbuffer);
5417}
5418
5419static void
5420move_begin(int i) {
5421 struct pte *pe = &ptes[i];
5422 struct partition *p = pe->part_table;
5423 uint new, first;
5424
5425 if (warn_geometry())
5426 return;
5427 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
5428 printf(_("Partition %d has no data area\n"), i + 1);
5429 return;
5430 }
5431 first = get_partition_start(pe);
5432 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5433 _("New beginning of data")) - pe->offset;
5434
5435 if (new != get_nr_sects(p)) {
5436 first = get_nr_sects(p) + get_start_sect(p) - new;
5437 set_nr_sects(p, first);
5438 set_start_sect(p, new);
5439 pe->changed = 1;
5440 }
5441}
5442
5443static void
5444xselect(void) {
5445 char c;
5446
5447 while(1) {
5448 putchar('\n');
5449 c = tolower(read_char(_("Expert command (m for help): ")));
5450 switch (c) {
5451 case 'a':
5452#ifdef CONFIG_FEATURE_SUN_LABEL
5453 if (sun_label)
5454 sun_set_alt_cyl();
5455#endif
5456 break;
5457 case 'b':
5458 if (dos_label)
5459 move_begin(get_partition(0, partitions));
5460 break;
5461 case 'c':
5462 user_cylinders = cylinders =
5463 read_int(1, cylinders, 1048576, 0,
5464 _("Number of cylinders"));
5465#ifdef CONFIG_FEATURE_SUN_LABEL
5466 if (sun_label)
5467 sun_set_ncyl(cylinders);
5468#endif
5469 if (dos_label)
5470 warn_cylinders();
5471 break;
5472 case 'd':
5473 print_raw();
5474 break;
5475 case 'e':
5476#ifdef CONFIG_FEATURE_SGI_LABEL
5477 if (sgi_label)
5478 sgi_set_xcyl();
5479 else
5480#endif
5481#ifdef CONFIG_FEATURE_SUN_LABEL
5482 if (sun_label)
5483 sun_set_xcyl();
5484 else
5485#endif
5486 if (dos_label)
5487 x_list_table(1);
5488 break;
5489 case 'f':
5490 if (dos_label)
5491 fix_partition_table_order();
5492 break;
5493 case 'g':
5494#ifdef CONFIG_FEATURE_SGI_LABEL
5495 create_sgilabel();
5496#endif
5497 break;
5498 case 'h':
5499 user_heads = heads = read_int(1, heads, 256, 0,
5500 _("Number of heads"));
5501 update_units();
5502 break;
5503 case 'i':
5504#ifdef CONFIG_FEATURE_SUN_LABEL
5505 if (sun_label)
5506 sun_set_ilfact();
5507#endif
5508 break;
5509 case 'o':
5510#ifdef CONFIG_FEATURE_SUN_LABEL
5511 if (sun_label)
5512 sun_set_rspeed();
5513#endif
5514 break;
5515 case 'p':
5516#ifdef CONFIG_FEATURE_SUN_LABEL
5517 if (sun_label)
5518 list_table(1);
5519 else
5520#endif
5521 x_list_table(0);
5522 break;
5523 case 'q':
5524 close(fd);
5525 printf("\n");
5526 exit(0);
5527 case 'r':
5528 return;
5529 case 's':
5530 user_sectors = sectors = read_int(1, sectors, 63, 0,
5531 _("Number of sectors"));
5532 if (dos_compatible_flag) {
5533 sector_offset = sectors;
5534 fprintf(stderr, _("Warning: setting "
5535 "sector offset for DOS "
5536 "compatiblity\n"));
5537 }
5538 update_units();
5539 break;
5540 case 'v':
5541 verify();
5542 break;
5543 case 'w':
5544 write_table(); /* does not return */
5545 break;
5546 case 'y':
5547#ifdef CONFIG_FEATURE_SUN_LABEL
5548 if (sun_label)
5549 sun_set_pcylcount();
5550#endif
5551 break;
5552 default:
5553 xmenu();
5554 }
5555 }
5556}
5557#endif /* ADVANCED mode */
5558
5559static int
5560is_ide_cdrom_or_tape(const char *device) {
5561 FILE *procf;
5562 char buf[100];
5563 struct stat statbuf;
5564 int is_ide = 0;
5565
5566 /* No device was given explicitly, and we are trying some
5567 likely things. But opening /dev/hdc may produce errors like
5568 "hdc: tray open or drive not ready"
5569 if it happens to be a CD-ROM drive. It even happens that
5570 the process hangs on the attempt to read a music CD.
5571 So try to be careful. This only works since 2.1.73. */
5572
5573 if (strncmp("/dev/hd", device, 7))
5574 return 0;
5575
5576 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5577 procf = fopen(buf, "r");
5578 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5579 is_ide = (!strncmp(buf, "cdrom", 5) ||
5580 !strncmp(buf, "tape", 4));
5581 else
5582 /* Now when this proc file does not exist, skip the
5583 device when it is read-only. */
5584 if (stat(device, &statbuf) == 0)
5585 is_ide = ((statbuf.st_mode & 0222) == 0);
5586
5587 if (procf)
5588 fclose(procf);
5589 return is_ide;
5590}
5591
5592static void
5593try(const char *device, int user_specified) {
5594 int gb;
5595
5596 disk_device = device;
5597 if (setjmp(listingbuf))
5598 return;
5599 if (!user_specified)
5600 if (is_ide_cdrom_or_tape(device))
5601 return;
5602 if ((fd = open(disk_device, type_open)) >= 0) {
5603 gb = get_boot(try_only);
5604 if (gb > 0) { /* I/O error */
5605 close(fd);
5606 } else if (gb < 0) { /* no DOS signature */
5607 list_disk_geometry();
5608 if (aix_label)
5609 return;
5610#ifdef CONFIG_FEATURE_OSF_LABEL
5611 if (btrydev(device) < 0)
5612#endif
5613 fprintf(stderr,
5614 _("Disk %s doesn't contain a valid "
5615 "partition table\n"), device);
5616 close(fd);
5617 } else {
5618 close(fd);
5619 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005620#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005621 if (!sun_label && partitions > 4)
5622 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005623#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005624 }
5625 } else {
5626 /* Ignore other errors, since we try IDE
5627 and SCSI hard disks which may not be
5628 installed on the system. */
5629 if (errno == EACCES) {
5630 fprintf(stderr, _("Cannot open %s\n"), device);
5631 return;
5632 }
5633 }
5634}
5635
5636/* for fdisk -l: try all things in /proc/partitions
5637 that look like a partition name (do not end in a digit) */
5638static void
5639tryprocpt(void) {
5640 FILE *procpt;
5641 char line[100], ptname[100], devname[120], *s;
5642 int ma, mi, sz;
5643
Manuel Novoa III cad53642003-03-19 09:13:01 +00005644 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005645
5646 while (fgets(line, sizeof(line), procpt)) {
5647 if (sscanf (line, " %d %d %d %[^\n ]",
5648 &ma, &mi, &sz, ptname) != 4)
5649 continue;
5650 for (s = ptname; *s; s++);
5651 if (isdigit(s[-1]))
5652 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005653 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005654 try(devname, 0);
5655 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005656#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005657 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005658#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005659}
5660
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005661#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005662static void
5663unknown_command(int c) {
5664 printf(_("%c: unknown command\n"), c);
5665}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005666#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005667
5668int fdisk_main(int argc, char **argv) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005669 int c;
5670#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5671 int optl = 0;
5672#endif
5673#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5674 int opts = 0;
5675#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005676 /*
5677 * Calls:
5678 * fdisk -v
5679 * fdisk -l [-b sectorsize] [-u] device ...
5680 * fdisk -s [partition] ...
5681 * fdisk [-b sectorsize] [-u] device
5682 *
5683 * Options -C, -H, -S set the geometry.
5684 *
5685 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005686 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5687#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5688 "s"
5689#endif
5690 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005691 switch (c) {
5692 case 'b':
5693 /* Ugly: this sector size is really per device,
5694 so cannot be combined with multiple disks,
5695 and te same goes for the C/H/S options.
5696 */
5697 sector_size = atoi(optarg);
5698 if (sector_size != 512 && sector_size != 1024 &&
5699 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005700 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005701 sector_offset = 2;
5702 user_set_sector_size = 1;
5703 break;
5704 case 'C':
5705 user_cylinders = atoi(optarg);
5706 break;
5707 case 'H':
5708 user_heads = atoi(optarg);
5709 if (user_heads <= 0 || user_heads >= 256)
5710 user_heads = 0;
5711 break;
5712 case 'S':
5713 user_sectors = atoi(optarg);
5714 if (user_sectors <= 0 || user_sectors >= 64)
5715 user_sectors = 0;
5716 break;
5717 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005718#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005719 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005720#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005721 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005722#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005723 case 's':
5724 opts = 1;
5725 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005726#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005727 case 'u':
5728 display_in_cyl_units = 0;
5729 break;
5730 case 'V':
5731 case 'v':
5732 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5733 return 0;
5734 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005735 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005736 }
5737 }
5738
5739#if 0
5740 printf(_("This kernel finds the sector size itself - "
5741 "-b option ignored\n"));
5742#else
5743 if (user_set_sector_size && argc-optind != 1)
5744 printf(_("Warning: the -b (set sector size) option should"
5745 " be used with one specified device\n"));
5746#endif
5747
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005748#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005749 if (optl) {
5750 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005751#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005752 type_open = O_RDONLY;
5753 if (argc > optind) {
5754 int k;
5755#if __GNUC__
5756 /* avoid gcc warning:
5757 variable `k' might be clobbered by `longjmp' */
5758 (void)&k;
5759#endif
5760 listing = 1;
5761 for (k=optind; k<argc; k++)
5762 try(argv[k], 1);
5763 } else {
5764 /* we no longer have default device names */
5765 /* but, we can use /proc/partitions instead */
5766 tryprocpt();
5767 }
5768 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005769#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005770 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005771#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005772
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005773#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005774 if (opts) {
5775 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005776 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005777
5778 nowarn = 1;
5779 type_open = O_RDONLY;
5780
5781 opts = argc - optind;
5782 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005783 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005784
5785 for (j = optind; j < argc; j++) {
5786 disk_device = argv[j];
5787 if ((fd = open(disk_device, type_open)) < 0)
5788 fdisk_fatal(unable_to_open);
5789 if (ioctl(fd, BLKGETSIZE, &size))
5790 fdisk_fatal(ioctl_error);
5791 close(fd);
5792 if (opts == 1)
5793 printf("%ld\n", size/2);
5794 else
5795 printf("%s: %ld\n", argv[j], size/2);
5796 }
5797 return 0;
5798 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005799#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005800
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005801#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005802 if (argc-optind == 1)
5803 disk_device = argv[optind];
5804 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005805 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005806
5807 get_boot(fdisk);
5808
5809#ifdef CONFIG_FEATURE_OSF_LABEL
5810 if (osf_label) {
5811 /* OSF label, and no DOS label */
5812 printf(_("Detected an OSF/1 disklabel on %s, entering "
5813 "disklabel mode.\n"),
5814 disk_device);
5815 bselect();
5816 osf_label = 0;
5817 /* If we return we may want to make an empty DOS label? */
5818 }
5819#endif
5820
5821 while (1) {
5822 putchar('\n');
5823 c = tolower(read_char(_("Command (m for help): ")));
5824 switch (c) {
5825 case 'a':
5826 if (dos_label)
5827 toggle_active(get_partition(1, partitions));
5828#ifdef CONFIG_FEATURE_SUN_LABEL
5829 else if (sun_label)
5830 toggle_sunflags(get_partition(1, partitions),
5831 0x01);
5832#endif
5833#ifdef CONFIG_FEATURE_SGI_LABEL
5834 else if (sgi_label)
5835 sgi_set_bootpartition(
5836 get_partition(1, partitions));
5837#endif
5838 else
5839 unknown_command(c);
5840 break;
5841 case 'b':
5842#ifdef CONFIG_FEATURE_SGI_LABEL
5843 if (sgi_label) {
5844 printf(_("\nThe current boot file is: %s\n"),
5845 sgi_get_bootfile());
5846 if (read_chars(_("Please enter the name of the "
5847 "new boot file: ")) == '\n')
5848 printf(_("Boot file unchanged\n"));
5849 else
5850 sgi_set_bootfile(line_ptr);
5851 } else
5852#endif
5853#ifdef CONFIG_FEATURE_OSF_LABEL
5854 bselect();
5855#endif
5856 break;
5857 case 'c':
5858 if (dos_label)
5859 toggle_dos_compatibility_flag();
5860#ifdef CONFIG_FEATURE_SUN_LABEL
5861 else if (sun_label)
5862 toggle_sunflags(get_partition(1, partitions),
5863 0x10);
5864#endif
5865#ifdef CONFIG_FEATURE_SGI_LABEL
5866 else if (sgi_label)
5867 sgi_set_swappartition(
5868 get_partition(1, partitions));
5869#endif
5870 else
5871 unknown_command(c);
5872 break;
5873 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005874 {
Eric Andersen040f4402003-07-30 08:40:37 +00005875 int j;
5876#ifdef CONFIG_FEATURE_SGI_LABEL
5877 /* If sgi_label then don't use get_existing_partition,
5878 let the user select a partition, since
5879 get_existing_partition() only works for Linux-like
5880 partition tables */
5881 if (!sgi_label) {
5882 j = get_existing_partition(1, partitions);
5883 } else {
5884 j = get_partition(1, partitions);
5885 }
5886#else
5887 j = get_existing_partition(1, partitions);
5888#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005889 if (j >= 0)
5890 delete_partition(j);
5891 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005892 break;
5893 case 'i':
5894#ifdef CONFIG_FEATURE_SGI_LABEL
5895 if (sgi_label)
5896 create_sgiinfo();
5897 else
5898#endif
5899 unknown_command(c);
5900 case 'l':
5901 list_types(get_sys_types());
5902 break;
5903 case 'm':
5904 menu();
5905 break;
5906 case 'n':
5907 new_partition();
5908 break;
5909 case 'o':
5910 create_doslabel();
5911 break;
5912 case 'p':
5913 list_table(0);
5914 break;
5915 case 'q':
5916 close(fd);
5917 printf("\n");
5918 return 0;
5919 case 's':
5920#ifdef CONFIG_FEATURE_SUN_LABEL
5921 create_sunlabel();
5922#endif
5923 break;
5924 case 't':
5925 change_sysid();
5926 break;
5927 case 'u':
5928 change_units();
5929 break;
5930 case 'v':
5931 verify();
5932 break;
5933 case 'w':
5934 write_table(); /* does not return */
5935 break;
5936#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5937 case 'x':
5938#ifdef CONFIG_FEATURE_SGI_LABEL
5939 if (sgi_label) {
5940 fprintf(stderr,
5941 _("\n\tSorry, no experts menu for SGI "
5942 "partition tables available.\n\n"));
5943 } else
5944#endif
5945
5946 xselect();
5947 break;
5948#endif
5949 default:
5950 unknown_command(c);
5951 menu();
5952 }
5953 }
5954 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005955#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005956}