blob: 71fbe074e4872f4a1f19e513f981d66c8420768f [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 *
10 * For detailed old history, see older versions.
11 * Contributions before 2001 by faith@cs.unc.edu, Michael Bischoff,
12 * LeBlanc@mcc.ac.uk, martin@cs.unc.edu, leisner@sdsp.mc.xerox.com,
13 * esr@snark.thyrsus.com, aeb@cwi.nl, quinlan@yggdrasil.com,
14 * fasten@cs.bonn.edu, orschaer@cip.informatik.uni-erlangen.de,
15 * jj@sunsite.mff.cuni.cz, fasten@shw.com, ANeuper@GUUG.de,
16 * kgw@suse.de, kalium@gmx.de, dhuggins@linuxcare.com,
17 * michal@ellpspace.math.ualberta.ca and probably others.
18 *
19 * Vladimir Oleynik <dzo@simtreas.ru> 2001,2002 Busybox port
20 */
21
22#define UTIL_LINUX_VERSION "2.11w"
23
24#define PROC_PARTITIONS "/proc/partitions"
25
26#include <sys/types.h>
27#include <sys/stat.h> /* stat */
28#include <ctype.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <errno.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <setjmp.h>
36#include <assert.h> /* assert */
37#include <getopt.h>
38
39#include <endian.h>
40#define u_char unsigned char
41#include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */
42#undef u_char
43
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000044#include <sys/ioctl.h>
45#include <sys/param.h>
46
Eric Andersenacd244a2002-12-11 03:49:33 +000047#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
48
49/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000050#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000051
52#include <sys/utsname.h>
53
54#include "busybox.h"
55
56#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
57
58#define DKTYPENAMES
59
60#define _(Text) Text
61
62#define BLKRRPART _IO(0x12,95) /* re-read partition table */
63#define BLKGETSIZE _IO(0x12,96) /* return device size */
64#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
65#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
66
67
68/*
69 fdisk.h
70*/
71
72#define DEFAULT_SECTOR_SIZE 512
73#define MAX_SECTOR_SIZE 2048
74#define SECTOR_SIZE 512 /* still used in BSD code */
75#define MAXIMUM_PARTS 60
76
77#define ACTIVE_FLAG 0x80
78
79#define EXTENDED 0x05
80#define WIN98_EXTENDED 0x0f
81#define LINUX_PARTITION 0x81
82#define LINUX_SWAP 0x82
83#define LINUX_NATIVE 0x83
84#define LINUX_EXTENDED 0x85
85#define LINUX_LVM 0x8e
86#define LINUX_RAID 0xfd
87
88#define SUNOS_SWAP 3
89#define WHOLE_DISK 5
90
91#define IS_EXTENDED(i) \
92 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
93
94#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
95
96#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
97#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
98
99#if defined(__GNUC__) || defined(HAS_LONG_LONG)
100typedef long long ext2_loff_t;
101#else
102typedef long ext2_loff_t;
103#endif
104
105/* including <linux/hdreg.h> also fails */
106struct hd_geometry {
107 unsigned char heads;
108 unsigned char sectors;
109 unsigned short cylinders;
110 unsigned long start;
111};
112
113#define HDIO_GETGEO 0x0301 /* get device geometry */
114
115
116struct systypes {
117 const unsigned char *name;
118};
119
120
121/*
122 * Raw disk label. For DOS-type partition tables the MBR,
123 * with descriptions of the primary partitions.
124 */
125static char MBRbuffer[MAX_SECTOR_SIZE];
126
127#ifdef CONFIG_FEATURE_SUN_LABEL
128static int sun_label; /* looking at sun disklabel */
129#else
130#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000131#endif
132#ifdef CONFIG_FEATURE_SGI_LABEL
133static int sgi_label; /* looking at sgi disklabel */
134#else
135#define sgi_label 0
136#endif
137#ifdef CONFIG_FEATURE_AIX_LABEL
138static int aix_label; /* looking at aix disklabel */
139#else
140#define aix_label 0
141#endif
142#ifdef CONFIG_FEATURE_OSF_LABEL
143static int osf_label; /* looking at OSF/1 disklabel */
144static int possibly_osf_label;
145#else
146#define osf_label 0
147#endif
148
149#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
150
151static uint heads, sectors, cylinders;
152static void update_units(void);
153
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000154
155/*
156 * return partition name - uses static storage unless buf is supplied
157 */
158static const char *
159partname(const char *dev, int pno, int lth) {
160 static char buffer[80];
161 const char *p;
162 int w, wp;
163 int bufsiz;
164 char *bufp;
165
166 bufp = buffer;
167 bufsiz = sizeof(buffer);
168
169 w = strlen(dev);
170 p = "";
171
172 if (isdigit(dev[w-1]))
173 p = "p";
174
175 /* devfs kludge - note: fdisk partition names are not supposed
176 to equal kernel names, so there is no reason to do this */
177 if (strcmp (dev + w - 4, "disc") == 0) {
178 w -= 4;
179 p = "part";
180 }
181
182 wp = strlen(p);
183
184 if (lth) {
185 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
186 lth-wp-2, w, dev, p, pno);
187 } else {
188 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
189 }
190 return bufp;
191}
192
193struct partition {
194 unsigned char boot_ind; /* 0x80 - active */
195 unsigned char head; /* starting head */
196 unsigned char sector; /* starting sector */
197 unsigned char cyl; /* starting cylinder */
198 unsigned char sys_ind; /* What partition type */
199 unsigned char end_head; /* end head */
200 unsigned char end_sector; /* end sector */
201 unsigned char end_cyl; /* end cylinder */
202 unsigned char start4[4]; /* starting sector counting from 0 */
203 unsigned char size4[4]; /* nr of sectors in partition */
204};
205
206enum failure {
207 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
208 unable_to_write
209};
210
211enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
212
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000213static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000214static int fd; /* the disk */
215static int partitions = 4; /* maximum partition + 1 */
216static uint display_in_cyl_units = 1;
217static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000218#ifdef CONFIG_FEATURE_FDISK_WRITABLE
219static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000220static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000221static void reread_partition_table(int leave);
222static void delete_partition(int i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000223static int get_partition(int warn, int max);
224static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000225static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000226#endif
227static const char *partition_type(unsigned char type);
228static void fdisk_fatal(enum failure why) __attribute__ ((noreturn));
229static void get_geometry(void);
230static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000231
232#define PLURAL 0
233#define SINGULAR 1
234
235#define hex_val(c) ({ \
236 char _c = (c); \
237 isdigit(_c) ? _c - '0' : \
238 tolower(_c) + 10 - 'a'; \
239 })
240
241
242#define LINE_LENGTH 800
243#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
244 (n) * sizeof(struct partition)))
245#define sector(s) ((s) & 0x3f)
246#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
247
248#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
249 ((h) + heads * cylinder(s,c)))
250#define set_hsc(h,s,c,sector) { \
251 s = sector % sectors + 1; \
252 sector /= sectors; \
253 h = sector % heads; \
254 sector /= heads; \
255 c = sector & 0xff; \
256 s |= (sector >> 2) & 0xc0; \
257 }
258
259
260static unsigned int get_start_sect(const struct partition *p);
261static unsigned int get_nr_sects(const struct partition *p);
262
263/*
264 * per partition table entry data
265 *
266 * The four primary partitions have the same sectorbuffer (MBRbuffer)
267 * and have NULL ext_pointer.
268 * Each logical partition table entry has two pointers, one for the
269 * partition and one link to the next one.
270 */
271static struct pte {
272 struct partition *part_table; /* points into sectorbuffer */
273 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000274#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000275 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000276#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000277 uint offset; /* disk sector number */
278 char *sectorbuffer; /* disk sector contents */
279} ptes[MAXIMUM_PARTS];
280
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000281
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000282#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000283static void
284set_all_unchanged(void) {
285 int i;
286
287 for (i = 0; i < MAXIMUM_PARTS; i++)
288 ptes[i].changed = 0;
289}
290
291static void
292set_changed(int i) {
293 ptes[i].changed = 1;
294}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000295#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000296
297#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
298static struct partition *
299get_part_table(int i) {
300 return ptes[i].part_table;
301}
302#endif
303
304static const char *
305str_units(int n) { /* n==1: use singular */
306 if (n == 1)
307 return display_in_cyl_units ? _("cylinder") : _("sector");
308 else
309 return display_in_cyl_units ? _("cylinders") : _("sectors");
310}
311
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000312static int
313valid_part_table_flag(const unsigned char *b) {
314 return (b[510] == 0x55 && b[511] == 0xaa);
315}
316
317#ifdef CONFIG_FEATURE_FDISK_WRITABLE
318static char line_buffer[LINE_LENGTH];
319
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000320/* read line; return 0 or first char */
321static int
322read_line(void)
323{
324 static int got_eof = 0;
325
326 fflush (stdout); /* requested by niles@scyld.com */
327 line_ptr = line_buffer;
328 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
329 if (feof(stdin))
330 got_eof++; /* user typed ^D ? */
331 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000332 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
333 exit(1);
334 }
335 return 0;
336 }
337 while (*line_ptr && !isgraph(*line_ptr))
338 line_ptr++;
339 return *line_ptr;
340}
341
342static char
343read_char(const char *mesg)
344{
345 do {
346 fputs(mesg, stdout);
347 } while (!read_line());
348 return *line_ptr;
349}
350
351static char
352read_chars(const char *mesg)
353{
354 fputs(mesg, stdout);
355 if (!read_line()) {
356 *line_ptr = '\n';
357 line_ptr[1] = 0;
358 }
359 return *line_ptr;
360}
361
362static int
363read_hex(const struct systypes *sys)
364{
365 int hex;
366
367 while (1)
368 {
369 read_char(_("Hex code (type L to list codes): "));
370 if (*line_ptr == 'l' || *line_ptr == 'L')
371 list_types(sys);
372 else if (isxdigit (*line_ptr))
373 {
374 hex = 0;
375 do
376 hex = hex << 4 | hex_val(*line_ptr++);
377 while (isxdigit(*line_ptr));
378 return hex;
379 }
380 }
381}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000382#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000383
384#ifdef CONFIG_FEATURE_AIX_LABEL
385/*
386 * Copyright (C) Andreas Neuper, Sep 1998.
387 * This file may be redistributed under
388 * the terms of the GNU Public License.
389 */
390
391typedef struct {
392 unsigned int magic; /* expect AIX_LABEL_MAGIC */
393 unsigned int fillbytes1[124];
394 unsigned int physical_volume_id;
395 unsigned int fillbytes2[124];
396} aix_partition;
397
398#define AIX_LABEL_MAGIC 0xc9c2d4c1
399#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
400#define AIX_INFO_MAGIC 0x00072959
401#define AIX_INFO_MAGIC_SWAPPED 0x59290700
402
403#define aixlabel ((aix_partition *)MBRbuffer)
404
405
406/*
407 Changes:
408 Sat Mar 20 09:51:38 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
409 Internationalization
410*/
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
518#else
519#error unknown architecture
520#endif
521
522#define BSD_BBSIZE 8192 /* size of boot area, with label */
523#define BSD_SBSIZE 8192 /* max size of fs superblock */
524
525struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000526 uint32_t d_magic; /* the magic number */
527 int16_t d_type; /* drive type */
528 int16_t d_subtype; /* controller/d_type specific */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000529 char d_typename[16]; /* type name, e.g. "eagle" */
530 char d_packname[16]; /* pack identifier */
531 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000532 uint32_t d_secsize; /* # of bytes per sector */
533 uint32_t d_nsectors; /* # of data sectors per track */
534 uint32_t d_ntracks; /* # of tracks per cylinder */
535 uint32_t d_ncylinders; /* # of data cylinders per unit */
536 uint32_t d_secpercyl; /* # of data sectors per cylinder */
537 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000538 /*
539 * Spares (bad sector replacements) below
540 * are not counted in d_nsectors or d_secpercyl.
541 * Spare sectors are assumed to be physical sectors
542 * which occupy space at the end of each track and/or cylinder.
543 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000544 uint16_t d_sparespertrack; /* # of spare sectors per track */
545 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000546 /*
547 * Alternate cylinders include maintenance, replacement,
548 * configuration description areas, etc.
549 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000550 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000551
552 /* hardware characteristics: */
553 /*
554 * d_interleave, d_trackskew and d_cylskew describe perturbations
555 * in the media format used to compensate for a slow controller.
556 * Interleave is physical sector interleave, set up by the formatter
557 * or controller when formatting. When interleaving is in use,
558 * logically adjacent sectors are not physically contiguous,
559 * but instead are separated by some number of sectors.
560 * It is specified as the ratio of physical sectors traversed
561 * per logical sector. Thus an interleave of 1:1 implies contiguous
562 * layout, while 2:1 implies that logical sector 0 is separated
563 * by one sector from logical sector 1.
564 * d_trackskew is the offset of sector 0 on track N
565 * relative to sector 0 on track N-1 on the same cylinder.
566 * Finally, d_cylskew is the offset of sector 0 on cylinder N
567 * relative to sector 0 on cylinder N-1.
568 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000569 uint16_t d_rpm; /* rotational speed */
570 uint16_t d_interleave; /* hardware sector interleave */
571 uint16_t d_trackskew; /* sector 0 skew, per track */
572 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
573 uint32_t d_headswitch; /* head switch time, usec */
574 uint32_t d_trkseek; /* track-to-track seek, usec */
575 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000576#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000577 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000578#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000579 uint32_t d_spare[NSPARE]; /* reserved for future use */
580 uint32_t d_magic2; /* the magic number (again) */
581 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000582 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000583 uint16_t d_npartitions; /* number of partitions in following */
584 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
585 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000586 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000587 uint32_t p_size; /* number of sectors in partition */
588 uint32_t p_offset; /* starting sector */
589 uint32_t p_fsize; /* filesystem basic fragment size */
590 uint8_t p_fstype; /* filesystem type, see below */
591 uint8_t p_frag; /* filesystem fragments per block */
592 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000593 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
594};
595
596/* d_type values: */
597#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
598#define BSD_DTYPE_MSCP 2 /* MSCP */
599#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
600#define BSD_DTYPE_SCSI 4 /* SCSI */
601#define BSD_DTYPE_ESDI 5 /* ESDI interface */
602#define BSD_DTYPE_ST506 6 /* ST506 etc. */
603#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
604#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
605#define BSD_DTYPE_FLOPPY 10 /* floppy */
606
607/* d_subtype values: */
608#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
609#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
610#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
611
612#ifdef DKTYPENAMES
613static const char * const xbsd_dktypenames[] = {
614 "unknown",
615 "SMD",
616 "MSCP",
617 "old DEC",
618 "SCSI",
619 "ESDI",
620 "ST506",
621 "HP-IB",
622 "HP-FL",
623 "type 9",
624 "floppy",
625 0
626};
627#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
628#endif
629
630/*
631 * Filesystem type and version.
632 * Used to interpret other filesystem-specific
633 * per-partition information.
634 */
635#define BSD_FS_UNUSED 0 /* unused */
636#define BSD_FS_SWAP 1 /* swap */
637#define BSD_FS_V6 2 /* Sixth Edition */
638#define BSD_FS_V7 3 /* Seventh Edition */
639#define BSD_FS_SYSV 4 /* System V */
640#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
641#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
642#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
643#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
644#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
645#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
646#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
647#define BSD_FS_ISOFS BSD_FS_ISO9660
648#define BSD_FS_BOOT 13 /* partition contains bootstrap */
649#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
650#define BSD_FS_HFS 15 /* Macintosh HFS */
651#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
652
653/* this is annoying, but it's also the way it is :-( */
654#ifdef __alpha__
655#define BSD_FS_EXT2 8 /* ext2 file system */
656#else
657#define BSD_FS_MSDOS 8 /* MS-DOS file system */
658#endif
659
660#ifdef DKTYPENAMES
661static const struct systypes xbsd_fstypes[] = {
662/* BSD_FS_UNUSED */ {"\x00" "unused"},
663/* BSD_FS_SWAP */ {"\x01" "swap"},
664/* BSD_FS_V6 */ {"\x02" "Version 6"},
665/* BSD_FS_V7 */ {"\x03" "Version 7"},
666/* BSD_FS_SYSV */ {"\x04" "System V"},
667/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
668/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
669/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
670#ifdef __alpha__
671/* BSD_FS_EXT2 */ {"\x08" "ext2"},
672#else
673/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
674#endif
675/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
676/* BSD_FS_OTHER */ {"\x0a" "unknown"},
677/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
678/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
679/* BSD_FS_BOOT */ {"\x0d" "boot"},
680/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
681/* BSD_FS_HFS */ {"\x0f" "HFS"},
682/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
683 { NULL }
684};
685#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
686
687#endif
688
689/*
690 * flags shared by various drives:
691 */
692#define BSD_D_REMOVABLE 0x01 /* removable media */
693#define BSD_D_ECC 0x02 /* supports ECC */
694#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
695#define BSD_D_RAMDISK 0x08 /* disk emulator */
696#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
697#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
698
699#endif /* OSF_LABEL */
700
701/*
702 * Copyright (C) Andreas Neuper, Sep 1998.
703 * This file may be modified and redistributed under
704 * the terms of the GNU Public License.
705 */
706
707struct device_parameter { /* 48 bytes */
708 unsigned char skew;
709 unsigned char gap1;
710 unsigned char gap2;
711 unsigned char sparecyl;
712 unsigned short pcylcount;
713 unsigned short head_vol0;
714 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
715 unsigned char cmd_tag_queue_depth;
716 unsigned char unused0;
717 unsigned short unused1;
718 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
719 unsigned short bytes;
720 unsigned short ilfact;
721 unsigned int flags; /* controller flags */
722 unsigned int datarate;
723 unsigned int retries_on_error;
724 unsigned int ms_per_word;
725 unsigned short xylogics_gap1;
726 unsigned short xylogics_syncdelay;
727 unsigned short xylogics_readdelay;
728 unsigned short xylogics_gap2;
729 unsigned short xylogics_readgate;
730 unsigned short xylogics_writecont;
731};
732
733#define SGI_VOLHDR 0x00
734/* 1 and 2 were used for drive types no longer supported by SGI */
735#define SGI_SWAP 0x03
736/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
737#define SGI_VOLUME 0x06
738#define SGI_EFS 0x07
739#define SGI_LVOL 0x08
740#define SGI_RLVOL 0x09
741#define SGI_XFS 0x0a
742#define SGI_XFSLOG 0x0b
743#define SGI_XLV 0x0c
744#define SGI_XVM 0x0d
745#define ENTIRE_DISK SGI_VOLUME
746/*
747 * controller flags
748 */
749#define SECTOR_SLIP 0x01
750#define SECTOR_FWD 0x02
751#define TRACK_FWD 0x04
752#define TRACK_MULTIVOL 0x08
753#define IGNORE_ERRORS 0x10
754#define RESEEK 0x20
755#define ENABLE_CMDTAGQ 0x40
756
757typedef struct {
758 unsigned int magic; /* expect SGI_LABEL_MAGIC */
759 unsigned short boot_part; /* active boot partition */
760 unsigned short swap_part; /* active swap partition */
761 unsigned char boot_file[16]; /* name of the bootfile */
762 struct device_parameter devparam; /* 1 * 48 bytes */
763 struct volume_directory { /* 15 * 16 bytes */
764 unsigned char vol_file_name[8]; /* a character array */
765 unsigned int vol_file_start; /* number of logical block */
766 unsigned int vol_file_size; /* number of bytes */
767 } directory[15];
768 struct sgi_partition { /* 16 * 12 bytes */
769 unsigned int num_sectors; /* number of blocks */
770 unsigned int start_sector; /* must be cylinder aligned */
771 unsigned int id;
772 } partitions[16];
773 unsigned int csum;
774 unsigned int fillbytes;
775} sgi_partition;
776
777typedef struct {
778 unsigned int magic; /* looks like a magic number */
779 unsigned int a2;
780 unsigned int a3;
781 unsigned int a4;
782 unsigned int b1;
783 unsigned short b2;
784 unsigned short b3;
785 unsigned int c[16];
786 unsigned short d[3];
787 unsigned char scsi_string[50];
788 unsigned char serial[137];
789 unsigned short check1816;
790 unsigned char installer[225];
791} sgiinfo;
792
793#define SGI_LABEL_MAGIC 0x0be5a941
794#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
795#define SGI_INFO_MAGIC 0x00072959
796#define SGI_INFO_MAGIC_SWAPPED 0x59290700
797#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000798 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000799#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000800 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000801
802#define sgilabel ((sgi_partition *)MBRbuffer)
803#define sgiparam (sgilabel->devparam)
804
805typedef struct {
806 unsigned char info[128]; /* Informative text string */
807 unsigned char spare0[14];
808 struct sun_info {
809 unsigned char spare1;
810 unsigned char id;
811 unsigned char spare2;
812 unsigned char flags;
813 } infos[8];
814 unsigned char spare1[246]; /* Boot information etc. */
815 unsigned short rspeed; /* Disk rotational speed */
816 unsigned short pcylcount; /* Physical cylinder count */
817 unsigned short sparecyl; /* extra sects per cylinder */
818 unsigned char spare2[4]; /* More magic... */
819 unsigned short ilfact; /* Interleave factor */
820 unsigned short ncyl; /* Data cylinder count */
821 unsigned short nacyl; /* Alt. cylinder count */
822 unsigned short ntrks; /* Tracks per cylinder */
823 unsigned short nsect; /* Sectors per track */
824 unsigned char spare3[4]; /* Even more magic... */
825 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000826 uint32_t start_cylinder;
827 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000828 } partitions[8];
829 unsigned short magic; /* Magic number */
830 unsigned short csum; /* Label xor'd checksum */
831} sun_partition;
832
833#define SUN_LABEL_MAGIC 0xDABE
834#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
835#define sunlabel ((sun_partition *)MBRbuffer)
836#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000837 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000838#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000839 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000840
841/*
842 * llseek.c -- stub calling the llseek system call
843 *
844 * Copyright (C) 1994 Remy Card. This file may be redistributed
845 * under the terms of the GNU Public License.
846 */
847
848
849#ifdef __linux__
850
851#ifdef HAVE_LLSEEK
852#include <syscall.h>
853
854#else /* HAVE_LLSEEK */
855
856#if defined(__alpha__) || defined(__ia64__)
857
858#define my_llseek lseek
859
860#else
Eric Andersenacd244a2002-12-11 03:49:33 +0000861#include <asm/unistd.h> /* for __NR__llseek */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000862
863static int _llseek (unsigned int, unsigned long,
864 unsigned long, ext2_loff_t *, unsigned int);
865
866#ifdef __NR__llseek
867
868static _syscall5(int,_llseek,unsigned int,f_d,unsigned long,offset_high,
869 unsigned long, offset_low,ext2_loff_t *,result,
870 unsigned int, origin)
871
872#else
873
874/* no __NR__llseek on compilation machine - might give it explicitly */
875static int _llseek (unsigned int f_d, unsigned long oh,
876 unsigned long ol, ext2_loff_t *result,
877 unsigned int origin) {
878 errno = ENOSYS;
879 return -1;
880}
881
882#endif
883
884static ext2_loff_t my_llseek (unsigned int f_d, ext2_loff_t offset,
885 unsigned int origin)
886{
887 ext2_loff_t result;
888 int retval;
889
890 retval = _llseek (f_d, ((unsigned long long) offset) >> 32,
891 ((unsigned long long) offset) & 0xffffffff,
892 &result, origin);
893 return (retval == -1 ? (ext2_loff_t) retval : result);
894}
895
896#endif /* __alpha__ */
897
898#endif /* HAVE_LLSEEK */
899
900static ext2_loff_t ext2_llseek (unsigned int f_d, ext2_loff_t offset,
901 unsigned int origin)
902{
903 ext2_loff_t result;
904 static int do_compat = 0;
905
906 if (!do_compat) {
907 result = my_llseek (f_d, offset, origin);
908 if (!(result == -1 && errno == ENOSYS))
909 return result;
910
911 /*
912 * Just in case this code runs on top of an old kernel
913 * which does not support the llseek system call
914 */
915 do_compat = 1;
916 /*
917 * Now try ordinary lseek.
918 */
919 }
920
921 if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
922 (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
923 return lseek(f_d, (off_t) offset, origin);
924
925 errno = EINVAL;
926 return -1;
927}
928
929#else /* !linux */
930
931static ext2_loff_t ext2_llseek (unsigned int f_d, ext2_loff_t offset,
932 unsigned int origin)
933{
934 if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
935 (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
936 errno = EINVAL;
937 return -1;
938 }
939 return lseek (f_d, (off_t) offset, origin);
940}
941
942#endif /* linux */
943
944
945#ifdef CONFIG_FEATURE_OSF_LABEL
946/*
947 Changes:
948 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
949
950 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
951 support for OSF/1 disklabels on Alpha.
952 Also fixed unaligned accesses in alpha_bootblock_checksum()
953*/
954
955#define FREEBSD_PARTITION 0xa5
956#define NETBSD_PARTITION 0xa9
957
958static void xbsd_delete_part (void);
959static void xbsd_new_part (void);
960static void xbsd_write_disklabel (void);
961static int xbsd_create_disklabel (void);
962static void xbsd_edit_disklabel (void);
963static void xbsd_write_bootstrap (void);
964static void xbsd_change_fstype (void);
965static int xbsd_get_part_index (int max);
966static int xbsd_check_new_partition (int *i);
967static void xbsd_list_types (void);
968static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
969static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d,
970 int pindex);
971static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
972static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
973
974#if defined (__alpha__)
975static void alpha_bootblock_checksum (char *boot);
976#endif
977
978#if !defined (__alpha__)
979static int xbsd_translate_fstype (int linux_type);
980static void xbsd_link_part (void);
981static struct partition *xbsd_part;
982static int xbsd_part_index;
983#endif
984
985#if defined (__alpha__)
986/* We access this through a u_int64_t * when checksumming */
987static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
988#else
989static char disklabelbuffer[BSD_BBSIZE];
990#endif
991
992static struct xbsd_disklabel xbsd_dlabel;
993
994#define bsd_cround(n) \
995 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
996
997/*
998 * Test whether the whole disk has BSD disk label magic.
999 *
1000 * Note: often reformatting with DOS-type label leaves the BSD magic,
1001 * so this does not mean that there is a BSD disk label.
1002 */
1003static int
1004check_osf_label(void) {
1005 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
1006 return 0;
1007 return 1;
1008}
1009
1010static void xbsd_print_disklabel(int);
1011
1012static int
Glenn L McGrath35631a62002-12-08 11:51:05 +00001013btrydev (const char * dev) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001014 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
1015 return -1;
1016 printf(_("\nBSD label for device: %s\n"), dev);
1017 xbsd_print_disklabel (0);
1018 return 0;
1019}
1020
1021static void
1022bmenu (void) {
1023 puts (_("Command action"));
1024 puts (_("\td\tdelete a BSD partition"));
1025 puts (_("\te\tedit drive data"));
1026 puts (_("\ti\tinstall bootstrap"));
1027 puts (_("\tl\tlist known filesystem types"));
1028 puts (_("\tm\tprint this menu"));
1029 puts (_("\tn\tadd a new BSD partition"));
1030 puts (_("\tp\tprint BSD partition table"));
1031 puts (_("\tq\tquit without saving changes"));
1032 puts (_("\tr\treturn to main menu"));
1033 puts (_("\ts\tshow complete disklabel"));
1034 puts (_("\tt\tchange a partition's filesystem id"));
1035 puts (_("\tu\tchange units (cylinders/sectors)"));
1036 puts (_("\tw\twrite disklabel to disk"));
1037#if !defined (__alpha__)
1038 puts (_("\tx\tlink BSD partition to non-BSD partition"));
1039#endif
1040}
1041
1042#if !defined (__alpha__)
1043static int
1044hidden(int type) {
1045 return type ^ 0x10;
1046}
1047
1048static int
1049is_bsd_partition_type(int type) {
1050 return (type == FREEBSD_PARTITION ||
1051 type == hidden(FREEBSD_PARTITION) ||
1052 type == NETBSD_PARTITION ||
1053 type == hidden(NETBSD_PARTITION));
1054}
1055#endif
1056
1057static void
1058bselect (void) {
1059#if !defined (__alpha__)
1060 int t, ss;
1061 struct partition *p;
1062
1063 for (t=0; t<4; t++) {
1064 p = get_part_table(t);
1065 if (p && is_bsd_partition_type(p->sys_ind)) {
1066 xbsd_part = p;
1067 xbsd_part_index = t;
1068 ss = get_start_sect(xbsd_part);
1069 if (ss == 0) {
1070 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"),
1071 partname(disk_device, t+1, 0));
1072 return;
1073 }
1074 printf (_("Reading disklabel of %s at sector %d.\n"),
1075 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
1076 if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
1077 if (xbsd_create_disklabel () == 0)
1078 return;
1079 break;
1080 }
1081 }
1082
1083 if (t == 4) {
1084 printf (_("There is no *BSD partition on %s.\n"), disk_device);
1085 return;
1086 }
1087
1088#elif defined (__alpha__)
1089
1090 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
1091 if (xbsd_create_disklabel () == 0)
1092 exit ( EXIT_SUCCESS );
1093
1094#endif
1095
1096 while (1) {
1097 putchar ('\n');
1098 switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
1099 case 'd':
1100 xbsd_delete_part ();
1101 break;
1102 case 'e':
1103 xbsd_edit_disklabel ();
1104 break;
1105 case 'i':
1106 xbsd_write_bootstrap ();
1107 break;
1108 case 'l':
1109 xbsd_list_types ();
1110 break;
1111 case 'n':
1112 xbsd_new_part ();
1113 break;
1114 case 'p':
1115 xbsd_print_disklabel (0);
1116 break;
1117 case 'q':
1118 close (fd);
1119 exit ( EXIT_SUCCESS );
1120 case 'r':
1121 return;
1122 case 's':
1123 xbsd_print_disklabel (1);
1124 break;
1125 case 't':
1126 xbsd_change_fstype ();
1127 break;
1128 case 'u':
1129 change_units();
1130 break;
1131 case 'w':
1132 xbsd_write_disklabel ();
1133 break;
1134#if !defined (__alpha__)
1135 case 'x':
1136 xbsd_link_part ();
1137 break;
1138#endif
1139 default:
1140 bmenu ();
1141 break;
1142 }
1143 }
1144}
1145
1146static void
1147xbsd_delete_part (void)
1148{
1149 int i;
1150
1151 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1152 xbsd_dlabel.d_partitions[i].p_size = 0;
1153 xbsd_dlabel.d_partitions[i].p_offset = 0;
1154 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1155 if (xbsd_dlabel.d_npartitions == i + 1)
1156 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1157 xbsd_dlabel.d_npartitions--;
1158}
1159
1160static void
1161xbsd_new_part (void)
1162{
1163 uint begin, end;
1164 char mesg[256];
1165 int i;
1166
1167 if (!xbsd_check_new_partition (&i))
1168 return;
1169
1170#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1171 begin = get_start_sect(xbsd_part);
1172 end = begin + get_nr_sects(xbsd_part) - 1;
1173#else
1174 begin = 0;
1175 end = xbsd_dlabel.d_secperunit - 1;
1176#endif
1177
1178 snprintf (mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1179 begin = read_int (bsd_cround (begin), bsd_cround (begin), bsd_cround (end),
1180 0, mesg);
1181
1182 if (display_in_cyl_units)
1183 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
1184
1185 snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1186 str_units(SINGULAR));
1187 end = read_int (bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1188 bsd_cround (begin), mesg);
1189
1190 if (display_in_cyl_units)
1191 end = end * xbsd_dlabel.d_secpercyl - 1;
1192
1193 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1194 xbsd_dlabel.d_partitions[i].p_offset = begin;
1195 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1196}
1197
1198static void
1199xbsd_print_disklabel (int show_all) {
1200 struct xbsd_disklabel *lp = &xbsd_dlabel;
1201 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001202 int i, j;
1203
1204 if (show_all) {
1205#if defined (__alpha__)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001206 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001207#else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001208 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001209#endif
1210 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001211 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001212 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001213 printf(_("type: %d\n"), lp->d_type);
1214 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1215 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1216 printf(_("flags:"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001217 if (lp->d_flags & BSD_D_REMOVABLE)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001218 printf(_(" removable"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001219 if (lp->d_flags & BSD_D_ECC)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001220 printf(_(" ecc"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001221 if (lp->d_flags & BSD_D_BADSECT)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001222 printf(_(" badsect"));
1223 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001224 /* On various machines the fields of *lp are short/int/long */
1225 /* In order to avoid problems, we cast them all to long. */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001226 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1227 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1228 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1229 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1230 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1231 printf(_("rpm: %d\n"), lp->d_rpm);
1232 printf(_("interleave: %d\n"), lp->d_interleave);
1233 printf(_("trackskew: %d\n"), lp->d_trackskew);
1234 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1235 printf(_("headswitch: %ld\t\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001236 (long) lp->d_headswitch);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001237 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001238 (long) lp->d_trkseek);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001239 printf(_("drivedata: "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001240 for (i = NDDATA - 1; i >= 0; i--)
1241 if (lp->d_drivedata[i])
1242 break;
1243 if (i < 0)
1244 i = 0;
1245 for (j = 0; j <= i; j++)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001246 printf("%ld ", (long) lp->d_drivedata[j]);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001247 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001248 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1249 printf(_("# start end size fstype [fsize bsize cpg]\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001250 pp = lp->d_partitions;
1251 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1252 if (pp->p_size) {
1253 if (display_in_cyl_units && lp->d_secpercyl) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001254 printf(" %c: %8ld%c %8ld%c %8ld%c ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001255 'a' + i,
1256 (long) pp->p_offset / lp->d_secpercyl + 1,
1257 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1258 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
1259 / lp->d_secpercyl,
1260 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1261 (long) pp->p_size / lp->d_secpercyl,
1262 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
1263 } else {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001264 printf(" %c: %8ld %8ld %8ld ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001265 'a' + i,
1266 (long) pp->p_offset,
1267 (long) pp->p_offset + pp->p_size - 1,
1268 (long) pp->p_size);
1269 }
1270 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001271 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001272 else
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001273 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001274 switch (pp->p_fstype) {
1275 case BSD_FS_UNUSED:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001276 printf(" %5ld %5ld %5.5s ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001277 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1278 break;
1279
1280 case BSD_FS_BSDFFS:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001281 printf(" %5ld %5ld %5d ",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001282 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
1283 pp->p_cpg);
1284 break;
1285
1286 default:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001287 printf("%22.22s", "");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001288 break;
1289 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001290 printf("\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291 }
1292 }
1293}
1294
1295static void
1296xbsd_write_disklabel (void) {
1297#if defined (__alpha__)
1298 printf (_("Writing disklabel to %s.\n"), disk_device);
1299 xbsd_writelabel (NULL, &xbsd_dlabel);
1300#else
1301 printf (_("Writing disklabel to %s.\n"),
1302 partname(disk_device, xbsd_part_index+1, 0));
1303 xbsd_writelabel (xbsd_part, &xbsd_dlabel);
1304#endif
1305 reread_partition_table(0); /* no exit yet */
1306}
1307
1308static int
1309xbsd_create_disklabel (void) {
1310 char c;
1311
1312#if defined (__alpha__)
1313 fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
1314#else
1315 fprintf (stderr, _("%s contains no disklabel.\n"),
1316 partname(disk_device, xbsd_part_index+1, 0));
1317#endif
1318
1319 while (1) {
1320 c = read_char (_("Do you want to create a disklabel? (y/n) "));
1321 if (c == 'y' || c == 'Y') {
1322 if (xbsd_initlabel (
1323#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__)
1324 NULL, &xbsd_dlabel, 0
1325#else
1326 xbsd_part, &xbsd_dlabel, xbsd_part_index
1327#endif
1328 ) == 1) {
1329 xbsd_print_disklabel (1);
1330 return 1;
1331 } else
1332 return 0;
1333 } else if (c == 'n')
1334 return 0;
1335 }
1336}
1337
1338static int
1339edit_int (int def, char *mesg)
1340{
1341 do {
1342 fputs (mesg, stdout);
1343 printf (" (%d): ", def);
1344 if (!read_line ())
1345 return def;
1346 }
1347 while (!isdigit (*line_ptr));
1348 return atoi (line_ptr);
1349}
1350
1351static void
1352xbsd_edit_disklabel (void)
1353{
1354 struct xbsd_disklabel *d;
1355
1356 d = &xbsd_dlabel;
1357
1358#if defined (__alpha__) || defined (__ia64__)
1359 d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,_("bytes/sector"));
1360 d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,_("sectors/track"));
1361 d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,_("tracks/cylinder"));
1362 d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,_("cylinders"));
1363#endif
1364
1365 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
1366 while (1)
1367 {
1368 d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
1369 _("sectors/cylinder"));
1370 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
1371 break;
1372
1373 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1374 }
1375 d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,_("rpm"));
1376 d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
1377 d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
1378 d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,_("cylinderskew"));
1379 d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,_("headswitch"));
1380 d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,_("track-to-track seek"));
1381
1382 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1383}
1384
1385static int
1386xbsd_get_bootstrap (char *path, void *ptr, int size)
1387{
1388 int fdb;
1389
1390 if ((fdb = open (path, O_RDONLY)) < 0)
1391 {
1392 perror (path);
1393 return 0;
1394 }
1395 if (read (fdb, ptr, size) < 0)
1396 {
1397 perror (path);
1398 close (fdb);
1399 return 0;
1400 }
1401 printf (" ... %s\n", path);
1402 close (fdb);
1403 return 1;
1404}
1405
1406static void
1407sync_disks (void)
1408{
1409 printf (_("\nSyncing disks.\n"));
1410 sync ();
1411 sleep (4);
1412}
1413
1414static void
1415xbsd_write_bootstrap (void)
1416{
1417 char *bootdir = BSD_LINUX_BOOTDIR;
1418 char path[MAXPATHLEN];
1419 char *dkbasename;
1420 struct xbsd_disklabel dl;
1421 char *d, *p, *e;
1422 int sector;
1423
1424 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1425 dkbasename = "sd";
1426 else
1427 dkbasename = "wd";
1428
1429 printf (_("Bootstrap: %sboot -> boot%s (%s): "),
1430 dkbasename, dkbasename, dkbasename);
1431 if (read_line ()) {
1432 line_ptr[strlen (line_ptr)-1] = '\0';
1433 dkbasename = line_ptr;
1434 }
1435 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1436 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1437 return;
1438
1439 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1440 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1441 bcopy (d, &dl, sizeof (struct xbsd_disklabel));
1442
1443 /* The disklabel will be overwritten by 0's from bootxx anyway */
1444 bzero (d, sizeof (struct xbsd_disklabel));
1445
1446 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1447 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
1448 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
1449 return;
1450
1451 e = d + sizeof (struct xbsd_disklabel);
1452 for (p=d; p < e; p++)
1453 if (*p) {
1454 fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
1455 exit ( EXIT_FAILURE );
1456 }
1457
1458 bcopy (&dl, d, sizeof (struct xbsd_disklabel));
1459
1460#if defined (__powerpc__) || defined (__hppa__)
1461 sector = 0;
1462#elif defined (__alpha__)
1463 sector = 0;
1464 alpha_bootblock_checksum (disklabelbuffer);
1465#else
1466 sector = get_start_sect(xbsd_part);
1467#endif
1468
1469 if (ext2_llseek (fd, (ext2_loff_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
1470 fdisk_fatal (unable_to_seek);
1471 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1472 fdisk_fatal (unable_to_write);
1473
1474#if defined (__alpha__)
1475 printf (_("Bootstrap installed on %s.\n"), disk_device);
1476#else
1477 printf (_("Bootstrap installed on %s.\n"),
1478 partname (disk_device, xbsd_part_index+1, 0));
1479#endif
1480
1481 sync_disks ();
1482}
1483
1484static void
1485xbsd_change_fstype (void)
1486{
1487 int i;
1488
1489 i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
1490 xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
1491}
1492
1493static int
1494xbsd_get_part_index (int max)
1495{
1496 char prompt[256];
1497 char l;
1498
1499 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1500 do
1501 l = tolower (read_char (prompt));
1502 while (l < 'a' || l > 'a' + max - 1);
1503 return l - 'a';
1504}
1505
1506static int
1507xbsd_check_new_partition (int *i) {
1508
1509 /* room for more? various BSD flavours have different maxima */
1510 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1511 int t;
1512
1513 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1514 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1515 break;
1516
1517 if (t == BSD_MAXPARTITIONS) {
1518 fprintf (stderr, _("The maximum number of partitions "
1519 "has been created\n"));
1520 return 0;
1521 }
1522 }
1523
1524 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1525
1526 if (*i >= xbsd_dlabel.d_npartitions)
1527 xbsd_dlabel.d_npartitions = (*i) + 1;
1528
1529 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
1530 fprintf (stderr, _("This partition already exists.\n"));
1531 return 0;
1532 }
1533
1534 return 1;
1535}
1536
1537static void
1538xbsd_list_types (void) {
1539 list_types (xbsd_fstypes);
1540}
1541
1542static u_short
1543xbsd_dkcksum (struct xbsd_disklabel *lp) {
1544 u_short *start, *end;
1545 u_short sum = 0;
1546
1547 start = (u_short *) lp;
1548 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1549 while (start < end)
1550 sum ^= *start++;
1551 return sum;
1552}
1553
1554static int
1555xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) {
1556 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001557
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001558 get_geometry ();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001559 bzero (d, sizeof (struct xbsd_disklabel));
1560
1561 d -> d_magic = BSD_DISKMAGIC;
1562
1563 if (strncmp (disk_device, "/dev/sd", 7) == 0)
1564 d -> d_type = BSD_DTYPE_SCSI;
1565 else
1566 d -> d_type = BSD_DTYPE_ST506;
1567
1568#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
1569 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
1570#endif
1571
1572#if !defined (__alpha__)
1573 d -> d_flags = BSD_D_DOSPART;
1574#else
1575 d -> d_flags = 0;
1576#endif
1577 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001578 d -> d_nsectors = sectors; /* sectors/track */
1579 d -> d_ntracks = heads; /* tracks/cylinder (heads) */
1580 d -> d_ncylinders = cylinders;
1581 d -> d_secpercyl = sectors * heads;/* sectors/cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001582 if (d -> d_secpercyl == 0)
1583 d -> d_secpercyl = 1; /* avoid segfaults */
1584 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
1585
1586 d -> d_rpm = 3600;
1587 d -> d_interleave = 1;
1588 d -> d_trackskew = 0;
1589 d -> d_cylskew = 0;
1590 d -> d_headswitch = 0;
1591 d -> d_trkseek = 0;
1592
1593 d -> d_magic2 = BSD_DISKMAGIC;
1594 d -> d_bbsize = BSD_BBSIZE;
1595 d -> d_sbsize = BSD_SBSIZE;
1596
1597#if !defined (__alpha__)
1598 d -> d_npartitions = 4;
1599 pp = &d -> d_partitions[2]; /* Partition C should be
1600 the NetBSD partition */
1601 pp -> p_offset = get_start_sect(p);
1602 pp -> p_size = get_nr_sects(p);
1603 pp -> p_fstype = BSD_FS_UNUSED;
1604 pp = &d -> d_partitions[3]; /* Partition D should be
1605 the whole disk */
1606 pp -> p_offset = 0;
1607 pp -> p_size = d -> d_secperunit;
1608 pp -> p_fstype = BSD_FS_UNUSED;
1609#elif defined (__alpha__)
1610 d -> d_npartitions = 3;
1611 pp = &d -> d_partitions[2]; /* Partition C should be
1612 the whole disk */
1613 pp -> p_offset = 0;
1614 pp -> p_size = d -> d_secperunit;
1615 pp -> p_fstype = BSD_FS_UNUSED;
1616#endif
1617
1618 return 1;
1619}
1620
1621/*
1622 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1623 * If it has the right magic, return 1.
1624 */
1625static int
1626xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1627{
1628 int t, sector;
1629
1630 /* p is used only to get the starting sector */
1631#if !defined (__alpha__)
1632 sector = (p ? get_start_sect(p) : 0);
1633#elif defined (__alpha__)
1634 sector = 0;
1635#endif
1636
1637 if (ext2_llseek (fd, (ext2_loff_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
1638 fdisk_fatal (unable_to_seek);
1639 if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
1640 fdisk_fatal (unable_to_read);
1641
1642 bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1643 d, sizeof (struct xbsd_disklabel));
1644
1645 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
1646 return 0;
1647
1648 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1649 d -> d_partitions[t].p_size = 0;
1650 d -> d_partitions[t].p_offset = 0;
1651 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
1652 }
1653
1654 if (d -> d_npartitions > BSD_MAXPARTITIONS)
1655 fprintf (stderr, _("Warning: too many partitions "
1656 "(%d, maximum is %d).\n"),
1657 d -> d_npartitions, BSD_MAXPARTITIONS);
1658 return 1;
1659}
1660
1661static int
1662xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1663{
1664 int sector;
1665
1666#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
1667 sector = get_start_sect(p) + BSD_LABELSECTOR;
1668#else
1669 sector = BSD_LABELSECTOR;
1670#endif
1671
1672 d -> d_checksum = 0;
1673 d -> d_checksum = xbsd_dkcksum (d);
1674
1675 /* This is necessary if we want to write the bootstrap later,
1676 otherwise we'd write the old disklabel with the bootstrap.
1677 */
1678 bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1679 sizeof (struct xbsd_disklabel));
1680
1681#if defined (__alpha__) && BSD_LABELSECTOR == 0
1682 alpha_bootblock_checksum (disklabelbuffer);
1683 if (ext2_llseek (fd, (ext2_loff_t) 0, SEEK_SET) == -1)
1684 fdisk_fatal (unable_to_seek);
1685 if (BSD_BBSIZE != write (fd, disklabelbuffer, BSD_BBSIZE))
1686 fdisk_fatal (unable_to_write);
1687#else
1688 if (ext2_llseek (fd, (ext2_loff_t) sector * SECTOR_SIZE + BSD_LABELOFFSET,
1689 SEEK_SET) == -1)
1690 fdisk_fatal (unable_to_seek);
1691 if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel)))
1692 fdisk_fatal (unable_to_write);
1693#endif
1694
1695 sync_disks ();
1696
1697 return 1;
1698}
1699
1700
1701#if !defined (__alpha__)
1702static int
1703xbsd_translate_fstype (int linux_type)
1704{
1705 switch (linux_type)
1706 {
1707 case 0x01: /* DOS 12-bit FAT */
1708 case 0x04: /* DOS 16-bit <32M */
1709 case 0x06: /* DOS 16-bit >=32M */
1710 case 0xe1: /* DOS access */
1711 case 0xe3: /* DOS R/O */
1712 case 0xf2: /* DOS secondary */
1713 return BSD_FS_MSDOS;
1714 case 0x07: /* OS/2 HPFS */
1715 return BSD_FS_HPFS;
1716 default:
1717 return BSD_FS_OTHER;
1718 }
1719}
1720
1721static void
1722xbsd_link_part (void)
1723{
1724 int k, i;
1725 struct partition *p;
1726
1727 k = get_partition (1, partitions);
1728
1729 if (!xbsd_check_new_partition (&i))
1730 return;
1731
1732 p = get_part_table(k);
1733
1734 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1735 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1736 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1737}
1738#endif
1739
1740#if defined (__alpha__)
1741
1742#if !defined(__GLIBC__)
1743typedef unsigned long long u_int64_t;
1744#endif
1745
1746static void
1747alpha_bootblock_checksum (char *boot)
1748{
1749 u_int64_t *dp, sum;
1750 int i;
1751
1752 dp = (u_int64_t *)boot;
1753 sum = 0;
1754 for (i = 0; i < 63; i++)
1755 sum += dp[i];
1756 dp[63] = sum;
1757}
1758#endif /* __alpha__ */
1759
1760#endif /* OSF_LABEL */
1761
1762#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1763static inline unsigned short
1764__swap16(unsigned short x) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001765 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001766}
1767
Eric Andersenacd244a2002-12-11 03:49:33 +00001768static inline uint32_t
1769__swap32(uint32_t x) {
1770 return (((uint32_t)(x) & 0xFF) << 24) | (((uint32_t)(x) & 0xFF00) << 8) | (((uint32_t)(x) & 0xFF0000) >> 8) | (((uint32_t)(x) & 0xFF000000) >> 24);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001771}
1772#endif
1773
1774#ifdef CONFIG_FEATURE_SGI_LABEL
1775/*
1776 *
1777 * fdisksgilabel.c
1778 *
1779 * Copyright (C) Andreas Neuper, Sep 1998.
1780 * This file may be modified and redistributed under
1781 * the terms of the GNU Public License.
1782 *
1783 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1784 * Internationalization
1785 */
1786
1787
1788static int sgi_other_endian;
1789static int debug;
1790static short sgi_volumes=1;
1791
1792/*
1793 * only dealing with free blocks here
1794 */
1795
1796typedef struct { int first; int last; } freeblocks;
1797static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1798
1799static void
1800setfreelist( int i, int f, int l ) {
1801 freelist[i].first = f;
1802 freelist[i].last = l;
1803}
1804
1805static void
1806add2freelist( int f, int l ) {
1807 int i = 0;
1808 for( ; i<17 ; i++ ) {
1809 if(freelist[i].last==0) break;
1810 }
1811 setfreelist( i, f, l );
1812}
1813
1814static void
1815clearfreelist(void) {
1816 int i = 0;
1817 for( ; i<17 ; i++ ) {
1818 setfreelist( i, 0, 0 );
1819 }
1820}
1821
1822static int
1823isinfreelist( int b ) {
1824 int i = 0;
1825 for( ; i<17 ; i++ ) {
1826 if (freelist[i].first <= b && freelist[i].last >= b) {
1827 return freelist[i].last;
1828 }
1829 }
1830 return 0;
1831}
1832 /* return last vacant block of this stride (never 0). */
1833 /* the '>=' is not quite correct, but simplifies the code */
1834/*
1835 * end of free blocks section
1836 */
1837
1838static const struct systypes sgi_sys_types[] = {
1839/* SGI_VOLHDR */ {"\x00" "SGI volhdr" },
1840/* 0x01 */ {"\x01" "SGI trkrepl" },
1841/* 0x02 */ {"\x02" "SGI secrepl" },
1842/* SGI_SWAP */ {"\x03" "SGI raw" },
1843/* 0x04 */ {"\x04" "SGI bsd" },
1844/* 0x05 */ {"\x05" "SGI sysv" },
1845/* ENTIRE_DISK */ {"\x06" "SGI volume" },
1846/* SGI_EFS */ {"\x07" "SGI efs" },
1847/* 0x08 */ {"\x08" "SGI lvol" },
1848/* 0x09 */ {"\x09" "SGI rlvol" },
1849/* SGI_XFS */ {"\x0a" "SGI xfs" },
1850/* SGI_XFSLOG */ {"\x0b" "SGI xfslog" },
1851/* SGI_XLV */ {"\x0c" "SGI xlv" },
1852/* SGI_XVM */ {"\x0d" "SGI xvm" },
1853/* LINUX_SWAP */ {"\x82" "Linux swap" },
1854/* LINUX_NATIVE */ {"\x83" "Linux native" },
1855/* LINUX_LVM */ {"\x8d" "Linux LVM" },
1856/* LINUX_RAID */ {"\xfd" "Linux RAID" },
1857 { NULL }
1858};
1859
1860
1861static int
1862sgi_get_nsect(void) {
1863 return SGI_SSWAP16(sgilabel->devparam.nsect);
1864}
1865
1866static int
1867sgi_get_ntrks(void) {
1868 return SGI_SSWAP16(sgilabel->devparam.ntrks);
1869}
1870
1871static int
1872sgi_get_pcylcount(void) {
1873 return SGI_SSWAP16(sgilabel->devparam.pcylcount);
1874}
1875
1876static void
1877sgi_nolabel(void) {
1878 sgilabel->magic = 0;
1879 sgi_label = 0;
1880 partitions = 4;
1881}
1882
1883static unsigned int
1884two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */ ) {
1885 int i=0;
1886 unsigned int sum=0;
1887
1888 size = size / sizeof( unsigned int );
1889 for( i=0; i<size; i++ )
1890 sum = sum - SGI_SSWAP32(base[i]);
1891 return sum;
1892}
1893
1894static int
1895check_sgi_label(void) {
1896 if (sizeof(sgilabel) > 512) {
1897 fprintf(stderr,
1898 _("According to MIPS Computer Systems, Inc the "
1899 "Label must not contain more than 512 bytes\n"));
1900 exit(1);
1901 }
1902
1903 if (sgilabel->magic != SGI_LABEL_MAGIC &&
1904 sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1905 sgi_label = 0;
1906 sgi_other_endian = 0;
1907 return 0;
1908 }
1909
1910 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1911 /*
1912 * test for correct checksum
1913 */
1914 if( two_s_complement_32bit_sum( (unsigned int*)sgilabel,
1915 sizeof(*sgilabel) ) )
1916 {
1917 fprintf( stderr, _("Detected sgi disklabel with wrong checksum.\n"));
1918 } else
1919 {
1920 heads = sgi_get_ntrks();
1921 cylinders = sgi_get_pcylcount();
1922 sectors = sgi_get_nsect();
1923 }
1924 update_units();
1925 sgi_label = 1;
1926 partitions= 16;
1927 sgi_volumes = 15;
1928 return 1;
1929}
1930
1931static int
1932sgi_get_start_sector( int i ) {
1933 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
1934}
1935
1936static int
1937sgi_get_num_sectors( int i ) {
1938 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
1939}
1940
1941static int
1942sgi_get_sysid( int i )
1943{
1944 return SGI_SSWAP32(sgilabel->partitions[i].id);
1945}
1946
1947static int
1948sgi_get_bootpartition(void)
1949{
1950 return SGI_SSWAP16(sgilabel->boot_part);
1951}
1952
1953static int
1954sgi_get_swappartition(void)
1955{
1956 return SGI_SSWAP16(sgilabel->swap_part);
1957}
1958
1959static void
1960sgi_list_table( int xtra ) {
1961 int i, w;
1962 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001963
1964 w = strlen( disk_device );
1965
1966 if( xtra ) {
1967 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1968 "%d cylinders, %d physical cylinders\n"
1969 "%d extra sects/cyl, interleave %d:1\n"
1970 "%s\n"
1971 "Units = %s of %d * 512 bytes\n\n"),
1972 disk_device, heads, sectors, cylinders,
1973 SGI_SSWAP16(sgiparam.pcylcount),
1974 SGI_SSWAP16(sgiparam.sparecyl),
1975 SGI_SSWAP16(sgiparam.ilfact),
1976 (char *)sgilabel,
1977 str_units(PLURAL), units_per_sector);
1978 } else {
1979 printf( _("\nDisk %s (SGI disk label): "
1980 "%d heads, %d sectors, %d cylinders\n"
1981 "Units = %s of %d * 512 bytes\n\n"),
1982 disk_device, heads, sectors, cylinders,
1983 str_units(PLURAL), units_per_sector );
1984 }
1985 printf(_("----- partitions -----\n"
1986 "Pt# %*s Info Start End Sectors Id System\n"),
1987 w + 1, _("Device"));
1988 for (i = 0 ; i < partitions; i++) {
1989 if( sgi_get_num_sectors(i) || debug ) {
Eric Andersenacd244a2002-12-11 03:49:33 +00001990 uint32_t start = sgi_get_start_sector(i);
1991 uint32_t len = sgi_get_num_sectors(i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001992 kpi++; /* only count nonempty partitions */
1993 printf(
1994 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1995/* fdisk part number */ i+1,
1996/* device */ partname(disk_device, kpi, w+2),
1997/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1998/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1999/* start */ (long) scround(start),
2000/* end */ (long) scround(start+len)-1,
2001/* no odd flag on end */ (long) len,
2002/* type id */ sgi_get_sysid(i),
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002003/* type name */ partition_type(sgi_get_sysid(i)));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002004 }
2005 }
2006 printf(_("----- Bootinfo -----\nBootfile: %s\n"
2007 "----- Directory Entries -----\n"),
2008 sgilabel->boot_file );
2009 for (i = 0 ; i < sgi_volumes; i++)
2010 {
2011 if (sgilabel->directory[i].vol_file_size)
2012 {
Eric Andersenacd244a2002-12-11 03:49:33 +00002013 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
2014 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002015 char*name = sgilabel->directory[i].vol_file_name;
2016 printf(_("%2d: %-10s sector%5u size%8u\n"),
2017 i, name, (unsigned int) start, (unsigned int) len);
2018 }
2019 }
2020}
2021
2022static void
2023sgi_set_bootpartition( int i )
2024{
2025 sgilabel->boot_part = SGI_SSWAP16(((short)i));
2026}
2027
2028static int
2029sgi_get_lastblock(void) {
2030 return heads * sectors * cylinders;
2031}
2032
2033static void
2034sgi_set_swappartition( int i ) {
2035 sgilabel->swap_part = SGI_SSWAP16(((short)i));
2036}
2037
2038static int
2039sgi_check_bootfile( const char* aFile ) {
2040 if( strlen( aFile ) < 3 ) /* "/a\n" is minimum */
2041 {
2042 printf( _("\nInvalid Bootfile!\n"
2043 "\tThe bootfile must be an absolute non-zero pathname,\n"
2044 "\te.g. \"/unix\" or \"/unix.save\".\n") );
2045 return 0;
2046 } else
2047 if( strlen( aFile ) > 16 )
2048 {
2049 printf( _("\n\tName of Bootfile too long: 16 bytes maximum.\n") );
2050 return 0;
2051 } else
2052 if( aFile[0] != '/' )
2053 {
2054 printf( _("\n\tBootfile must have a fully qualified pathname.\n") );
2055 return 0;
2056 }
2057 if( strncmp( aFile, sgilabel->boot_file, 16 ) )
2058 {
2059 printf( _("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
2060 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n") );
2061 /* filename is correct and did change */
2062 return 1;
2063 }
2064 return 0; /* filename did not change */
2065}
2066
2067static const char *
2068sgi_get_bootfile(void) {
2069 return sgilabel->boot_file;
2070}
2071
2072static void
2073sgi_set_bootfile( const char* aFile )
2074{
2075 int i = 0;
2076 if( sgi_check_bootfile( aFile ) )
2077 {
2078 while( i<16 )
2079 {
2080 if( (aFile[i] != '\n') /* in principle caught again by next line */
2081 && (strlen( aFile ) > i ) )
2082 sgilabel->boot_file[i] = aFile[i];
2083 else
2084 sgilabel->boot_file[i] = 0;
2085 i++;
2086 }
2087 printf( _("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file );
2088 }
2089}
2090
2091static void
2092create_sgiinfo(void)
2093{
2094 /* I keep SGI's habit to write the sgilabel to the second block */
2095 sgilabel->directory[0].vol_file_start = SGI_SSWAP32( 2 );
2096 sgilabel->directory[0].vol_file_size = SGI_SSWAP32( sizeof( sgiinfo ) );
2097 strncpy( sgilabel->directory[0].vol_file_name, "sgilabel", 8 );
2098}
2099
2100static sgiinfo * fill_sgiinfo(void);
2101
2102static void
2103sgi_write_table(void)
2104{
2105 sgilabel->csum = 0;
2106 sgilabel->csum = SGI_SSWAP32( two_s_complement_32bit_sum(
2107 (unsigned int*)sgilabel,
2108 sizeof(*sgilabel) ) );
2109 assert( two_s_complement_32bit_sum(
2110 (unsigned int*)sgilabel, sizeof(*sgilabel) ) == 0 );
2111 if( lseek(fd, 0, SEEK_SET) < 0 )
2112 fdisk_fatal(unable_to_seek);
2113 if( write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE )
2114 fdisk_fatal(unable_to_write);
2115 if( ! strncmp( sgilabel->directory[0].vol_file_name, "sgilabel",8 ) )
2116 {
2117 /*
2118 * keep this habbit of first writing the "sgilabel".
2119 * I never tested whether it works without (AN 981002).
2120 */
2121 sgiinfo*info = fill_sgiinfo(); /* fills the block appropriately */
2122 int infostartblock = SGI_SSWAP32( sgilabel->directory[0].vol_file_start );
2123 if( ext2_llseek(fd, (ext2_loff_t)infostartblock*
2124 SECTOR_SIZE, SEEK_SET) < 0 )
2125 fdisk_fatal(unable_to_seek);
2126 if( write(fd, info, SECTOR_SIZE) != SECTOR_SIZE )
2127 fdisk_fatal(unable_to_write);
2128 free( info );
2129 }
2130}
2131
2132static int
2133compare_start( int *x, int *y ) {
2134 /*
2135 * sort according to start sectors
2136 * and prefers largest partition:
2137 * entry zero is entire disk entry
2138 */
2139 int i = *x;
2140 int j = *y;
2141 int a = sgi_get_start_sector(i);
2142 int b = sgi_get_start_sector(j);
2143 int c = sgi_get_num_sectors(i);
2144 int d = sgi_get_num_sectors(j);
2145 if( a == b )
2146 {
2147 return( d - c );
2148 }
2149 return( a - b );
2150}
2151
2152
2153static int
2154verify_sgi( int verbose )
2155{
2156 int Index[16]; /* list of valid partitions */
2157 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2158 int entire = 0, i = 0; /* local counters */
2159 int start = 0;
2160 int gap = 0; /* count unused blocks */
2161 int lastblock = sgi_get_lastblock();
2162 /*
2163 */
2164 clearfreelist();
2165 for( i=0; i<16; i++ )
2166 {
2167 if( sgi_get_num_sectors(i)!=0 )
2168 {
2169 Index[sortcount++]=i;
2170 if( sgi_get_sysid(i) == ENTIRE_DISK )
2171 {
2172 if( entire++ == 1 )
2173 {
2174 if(verbose)
2175 printf(_("More than one entire disk entry present.\n"));
2176 }
2177 }
2178 }
2179 }
2180 if( sortcount == 0 )
2181 {
2182 if(verbose)
2183 printf(_("No partitions defined\n"));
2184 return lastblock;
2185 }
2186 qsort( Index, sortcount, sizeof(Index[0]), (void*)compare_start );
2187 if( sgi_get_sysid( Index[0] ) == ENTIRE_DISK )
2188 {
2189 if( ( Index[0] != 10 ) && verbose )
2190 printf( _("IRIX likes when Partition 11 covers the entire disk.\n") );
2191 if( ( sgi_get_start_sector( Index[0] ) != 0 ) && verbose )
2192 printf( _("The entire disk partition should start at block 0,\nnot "
2193 "at diskblock %d.\n"), sgi_get_start_sector(Index[0] ) );
2194 if(debug) /* I do not understand how some disks fulfil it */
2195 if( ( sgi_get_num_sectors( Index[0] ) != lastblock ) && verbose )
2196 printf( _("The entire disk partition is only %d diskblock large,\n"
2197 "but the disk is %d diskblocks long.\n"),
2198 sgi_get_num_sectors( Index[0] ), lastblock );
2199 lastblock = sgi_get_num_sectors( Index[0] );
2200 } else
2201 {
2202 if( verbose )
2203 printf( _("One Partition (#11) should cover the entire disk.\n") );
2204 if(debug>2)
2205 printf( "sysid=%d\tpartition=%d\n",
2206 sgi_get_sysid( Index[0] ), Index[0]+1 );
2207 }
2208 for( i=1, start=0; i<sortcount; i++ )
2209 {
2210 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2211 if( (sgi_get_start_sector( Index[i] ) % cylsize) != 0 )
2212 {
2213 if(debug) /* I do not understand how some disks fulfil it */
2214 if( verbose )
2215 printf( _("Partition %d does not start on cylinder boundary.\n"),
2216 Index[i]+1 );
2217 }
2218 if( sgi_get_num_sectors( Index[i] ) % cylsize != 0 )
2219 {
2220 if(debug) /* I do not understand how some disks fulfil it */
2221 if( verbose )
2222 printf( _("Partition %d does not end on cylinder boundary.\n"),
2223 Index[i]+1 );
2224 }
2225 /* We cannot handle several "entire disk" entries. */
2226 if( sgi_get_sysid( Index[i] ) == ENTIRE_DISK ) continue;
2227 if( start > sgi_get_start_sector( Index[i] ) )
2228 {
2229 if( verbose )
2230 printf( _("The Partition %d and %d overlap by %d sectors.\n"),
2231 Index[i-1]+1, Index[i]+1,
2232 start - sgi_get_start_sector( Index[i] ) );
2233 if( gap > 0 ) gap = -gap;
2234 if( gap == 0 ) gap = -1;
2235 }
2236 if( start < sgi_get_start_sector( Index[i] ) )
2237 {
2238 if( verbose )
2239 printf( _("Unused gap of %8d sectors - sectors %8d-%d\n"),
2240 sgi_get_start_sector( Index[i] ) - start,
2241 start, sgi_get_start_sector( Index[i] )-1 );
2242 gap += sgi_get_start_sector( Index[i] ) - start;
2243 add2freelist( start, sgi_get_start_sector( Index[i] ) );
2244 }
2245 start = sgi_get_start_sector( Index[i] )
2246 + sgi_get_num_sectors( Index[i] );
2247 if(debug>1)
2248 {
2249 if( verbose )
2250 printf( "%2d:%12d\t%12d\t%12d\n", Index[i],
2251 sgi_get_start_sector(Index[i]),
2252 sgi_get_num_sectors(Index[i]),
2253 sgi_get_sysid(Index[i]) );
2254 }
2255 }
2256 if( ( start < lastblock ) )
2257 {
2258 if( verbose )
2259 printf( _("Unused gap of %8d sectors - sectors %8d-%d\n"),
2260 lastblock - start, start, lastblock-1 );
2261 gap += lastblock - start;
2262 add2freelist( start, lastblock );
2263 }
2264 /*
2265 * Done with arithmetics
2266 * Go for details now
2267 */
2268 if( verbose )
2269 {
2270 if( !sgi_get_num_sectors( sgi_get_bootpartition() ) )
2271 {
2272 printf( _("\nThe boot partition does not exist.\n") );
2273 }
2274 if( !sgi_get_num_sectors( sgi_get_swappartition() ) )
2275 {
2276 printf( _("\nThe swap partition does not exist.\n") );
2277 } else
2278 if( ( sgi_get_sysid( sgi_get_swappartition() ) != SGI_SWAP )
2279 && ( sgi_get_sysid( sgi_get_swappartition() ) != LINUX_SWAP ) )
2280 {
2281 printf( _("\nThe swap partition has no swap type.\n") );
2282 }
2283 if( sgi_check_bootfile( "/unix" ) )
2284 {
2285 printf( _("\tYou have chosen an unusual boot file name.\n") );
2286 }
2287 }
2288 return gap;
2289}
2290
2291static int
2292sgi_gaps(void) {
2293 /*
2294 * returned value is:
2295 * = 0 : disk is properly filled to the rim
2296 * < 0 : there is an overlap
2297 * > 0 : there is still some vacant space
2298 */
2299 return verify_sgi(0);
2300}
2301
2302static void
2303sgi_change_sysid( int i, int sys )
2304{
2305 if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
2306 {
2307 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2308 return;
2309 }
2310 if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2311 && (sgi_get_start_sector(i)<1) )
2312 {
2313 read_chars(
2314 _("It is highly recommended that the partition at offset 0\n"
2315 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2316 "retrieve from its directory standalone tools like sash and fx.\n"
2317 "Only the \"SGI volume\" entire disk section may violate this.\n"
2318 "Type YES if you are sure about tagging this partition differently.\n"));
2319 if (strcmp (line_ptr, _("YES\n")))
2320 return;
2321 }
2322 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2323}
2324
2325/* returns partition index of first entry marked as entire disk */
2326static int
2327sgi_entire(void) {
2328 int i=0;
2329 for( i=0; i<16; i++ )
2330 if( sgi_get_sysid(i) == SGI_VOLUME )
2331 return i;
2332 return -1;
2333}
2334
2335static void
2336sgi_set_partition( int i, uint start, uint length, int sys ) {
2337 sgilabel->partitions[i].id =
2338 SGI_SSWAP32( sys );
2339 sgilabel->partitions[i].num_sectors =
2340 SGI_SSWAP32( length );
2341 sgilabel->partitions[i].start_sector =
2342 SGI_SSWAP32( start );
2343 set_changed(i);
2344 if( sgi_gaps() < 0 ) /* rebuild freelist */
2345 printf(_("Do You know, You got a partition overlap on the disk?\n"));
2346}
2347
2348static void
2349sgi_set_entire(void) {
2350 int n;
2351 for( n=10; n<partitions; n++ ) {
2352 if(!sgi_get_num_sectors( n ) ) {
2353 sgi_set_partition( n, 0, sgi_get_lastblock(), SGI_VOLUME );
2354 break;
2355 }
2356 }
2357}
2358
2359static void
2360sgi_set_volhdr(void)
2361{
2362 int n;
2363 for( n=8; n<partitions; n++ )
2364 {
2365 if(!sgi_get_num_sectors( n ) )
2366 {
2367 /*
2368 * 5 cylinders is an arbitrary value I like
2369 * IRIX 5.3 stored files in the volume header
2370 * (like sash, symmon, fx, ide) with ca. 3200
2371 * sectors.
2372 */
2373 if( heads * sectors * 5 < sgi_get_lastblock() )
2374 sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
2375 break;
2376 }
2377 }
2378}
2379
2380static void
2381sgi_delete_partition( int i )
2382{
2383 sgi_set_partition( i, 0, 0, 0 );
2384}
2385
2386static void
2387sgi_add_partition( int n, int sys )
2388{
2389 char mesg[256];
2390 int first=0, last=0;
2391
2392 if( n == 10 ) {
2393 sys = SGI_VOLUME;
2394 } else if ( n == 8 ) {
2395 sys = 0;
2396 }
2397 if( sgi_get_num_sectors(n) )
2398 {
2399 printf(_("Partition %d is already defined. Delete "
2400 "it before re-adding it.\n"), n + 1);
2401 return;
2402 }
2403 if( (sgi_entire() == -1)
2404 && (sys != SGI_VOLUME) )
2405 {
2406 printf(_("Attempting to generate entire disk entry automatically.\n"));
2407 sgi_set_entire();
2408 sgi_set_volhdr();
2409 }
2410 if( (sgi_gaps() == 0)
2411 && (sys != SGI_VOLUME) )
2412 {
2413 printf(_("The entire disk is already covered with partitions.\n"));
2414 return;
2415 }
2416 if( sgi_gaps() < 0 )
2417 {
2418 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2419 return;
2420 }
2421 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2422 for(;;) {
2423 if(sys == SGI_VOLUME) {
2424 last = sgi_get_lastblock();
2425 first = read_int(0, 0, last-1, 0, mesg);
2426 if( first != 0 ) {
2427 printf(_("It is highly recommended that eleventh partition\n"
2428 "covers the entire disk and is of type `SGI volume'\n"));
2429 }
2430 } else {
2431 first = freelist[0].first;
2432 last = freelist[0].last;
2433 first = read_int(scround(first), scround(first), scround(last)-1,
2434 0, mesg);
2435 }
2436 if (display_in_cyl_units)
2437 first *= units_per_sector;
2438 else
2439 first = first; /* align to cylinder if you know how ... */
2440 if( !last )
2441 last = isinfreelist(first);
2442 if( last == 0 ) {
2443 printf(_("You will get a partition overlap on the disk. "
2444 "Fix it first!\n"));
2445 } else
2446 break;
2447 }
2448 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2449 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2450 scround(first), mesg)+1;
2451 if (display_in_cyl_units)
2452 last *= units_per_sector;
2453 else
2454 last = last; /* align to cylinder if You know how ... */
2455 if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
2456 printf(_("It is highly recommended that eleventh partition\n"
2457 "covers the entire disk and is of type `SGI volume'\n"));
2458 sgi_set_partition( n, first, last-first, sys );
2459}
2460
2461static void
2462create_sgilabel(void)
2463{
2464 struct hd_geometry geometry;
2465 struct { int start;
2466 int nsect;
2467 int sysid; } old[4];
2468 int i=0;
2469 fprintf( stderr,
2470 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2471 "until you decide to write them. After that, of course, the previous\n"
2472 "content will be unrecoverably lost.\n\n"));
2473
2474 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
2475
2476#ifdef HDIO_REQ
2477 if (!ioctl(fd, HDIO_REQ, &geometry))
2478#else
2479 if (!ioctl(fd, HDIO_GETGEO, &geometry))
2480#endif
2481 {
2482 heads = geometry.heads;
2483 sectors = geometry.sectors;
2484 cylinders = geometry.cylinders;
2485 }
2486 for (i = 0; i < 4; i++)
2487 {
2488 old[i].sysid = 0;
2489 if( valid_part_table_flag(MBRbuffer) )
2490 {
2491 if( get_part_table(i)->sys_ind )
2492 {
2493 old[i].sysid = get_part_table(i)->sys_ind;
2494 old[i].start = get_start_sect( get_part_table(i) );
2495 old[i].nsect = get_nr_sects( get_part_table(i) );
2496 printf( _("Trying to keep parameters of partition %d.\n"), i );
2497 if( debug )
2498 printf( _("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2499 old[i].sysid, old[i].start, old[i].nsect );
2500 }
2501 }
2502 }
2503 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2504 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2505 sgilabel->boot_part = SGI_SSWAP16(0);
2506 sgilabel->swap_part = SGI_SSWAP16(1);
2507
2508 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2509 memset(sgilabel->boot_file, 0, 16);
2510 strcpy(sgilabel->boot_file, "/unix");
2511
2512 sgilabel->devparam.skew = (0);
2513 sgilabel->devparam.gap1 = (0);
2514 sgilabel->devparam.gap2 = (0);
2515 sgilabel->devparam.sparecyl = (0);
2516 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2517 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2518 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
2519 /* tracks/cylinder (heads) */
2520 sgilabel->devparam.cmd_tag_queue_depth = (0);
2521 sgilabel->devparam.unused0 = (0);
2522 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2523 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
2524 /* sectors/track */
2525 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2526 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2527 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
2528 IGNORE_ERRORS|RESEEK);
2529 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2530 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2531 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2532 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2533 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2534 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2535 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2536 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2537 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2538 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2539 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2540 sgi_label = 1;
2541 partitions = 16;
2542 sgi_volumes = 15;
2543 sgi_set_entire();
2544 sgi_set_volhdr();
2545 for (i = 0; i < 4; i++)
2546 {
2547 if( old[i].sysid )
2548 {
2549 sgi_set_partition( i, old[i].start, old[i].nsect, old[i].sysid );
2550 }
2551 }
2552}
2553
2554static void
2555sgi_set_xcyl(void)
2556{
2557 /* do nothing in the beginning */
2558}
2559
2560/* _____________________________________________________________
2561 */
2562
2563static sgiinfo*
2564fill_sgiinfo(void)
2565{
2566 sgiinfo*info=calloc( 1, sizeof(sgiinfo) );
2567 info->magic=SGI_SSWAP32(SGI_INFO_MAGIC);
2568 info->b1=SGI_SSWAP32(-1);
2569 info->b2=SGI_SSWAP16(-1);
2570 info->b3=SGI_SSWAP16(1);
2571 /* You may want to replace this string !!!!!!! */
2572 strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" );
2573 strcpy( info->serial, "0000" );
2574 info->check1816 = SGI_SSWAP16(18*256 +16 );
2575 strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
2576 return info;
2577}
2578#endif /* SGI_LABEL */
2579
2580
2581#ifdef CONFIG_FEATURE_SUN_LABEL
2582/*
2583 * fdisksunlabel.c
2584 *
2585 * I think this is mostly, or entirely, due to
2586 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2587 *
2588 * Merged with fdisk for other architectures, aeb, June 1998.
2589 *
2590 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2591 * Internationalization
2592 */
2593
2594
2595static int sun_other_endian;
2596static int scsi_disk;
2597static int floppy;
2598
2599#ifndef IDE0_MAJOR
2600#define IDE0_MAJOR 3
2601#endif
2602#ifndef IDE1_MAJOR
2603#define IDE1_MAJOR 22
2604#endif
2605static void guess_device_type(void) {
2606 struct stat bootstat;
2607
2608 if (fstat (fd, &bootstat) < 0) {
2609 scsi_disk = 0;
2610 floppy = 0;
2611 } else if (S_ISBLK(bootstat.st_mode)
2612 && ((bootstat.st_rdev >> 8) == IDE0_MAJOR ||
2613 (bootstat.st_rdev >> 8) == IDE1_MAJOR)) {
2614 scsi_disk = 0;
2615 floppy = 0;
2616 } else if (S_ISBLK(bootstat.st_mode)
2617 && (bootstat.st_rdev >> 8) == FLOPPY_MAJOR) {
2618 scsi_disk = 0;
2619 floppy = 1;
2620 } else {
2621 scsi_disk = 1;
2622 floppy = 0;
2623 }
2624}
2625
2626static const struct systypes sun_sys_types[] = {
2627/* 0 */ {"\x00" "Empty" },
2628/* 1 */ {"\x01" "Boot" },
2629/* 2 */ {"\x02" "SunOS root" },
2630/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
2631/* 4 */ {"\x04" "SunOS usr" },
2632/* WHOLE_DISK */ {"\x05" "Whole disk" },
2633/* 6 */ {"\x06" "SunOS stand" },
2634/* 7 */ {"\x07" "SunOS var" },
2635/* 8 */ {"\x08" "SunOS home" },
2636/* LINUX_SWAP */ {"\x82" "Linux swap" },
2637/* LINUX_NATIVE */ {"\x83" "Linux native" },
2638/* 0x8e */ {"\x8e" "Linux LVM" },
2639/* New (2.2.x) raid partition with autodetect using persistent superblock */
2640/* 0xfd */ {"\xfd" "Linux raid autodetect" },
2641 { NULL }
2642};
2643
2644
2645static void
2646set_sun_partition(int i, uint start, uint stop, int sysid) {
2647 sunlabel->infos[i].id = sysid;
2648 sunlabel->partitions[i].start_cylinder =
2649 SUN_SSWAP32(start / (heads * sectors));
2650 sunlabel->partitions[i].num_sectors =
2651 SUN_SSWAP32(stop - start);
2652 set_changed(i);
2653}
2654
2655static void
2656sun_nolabel(void) {
2657 sun_label = 0;
2658 sunlabel->magic = 0;
2659 partitions = 4;
2660}
2661
2662static int
2663check_sun_label(void) {
2664 unsigned short *ush;
2665 int csum;
2666
2667 if (sunlabel->magic != SUN_LABEL_MAGIC &&
2668 sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
2669 sun_label = 0;
2670 sun_other_endian = 0;
2671 return 0;
2672 }
2673 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2674 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2675 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2676 if (csum) {
2677 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2678 "Probably you'll have to set all the values,\n"
2679 "e.g. heads, sectors, cylinders and partitions\n"
2680 "or force a fresh label (s command in main menu)\n"));
2681 } else {
2682 heads = SUN_SSWAP16(sunlabel->ntrks);
2683 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2684 sectors = SUN_SSWAP16(sunlabel->nsect);
2685 }
2686 update_units();
2687 sun_label = 1;
2688 partitions = 8;
2689 return 1;
2690}
2691
2692static const struct sun_predefined_drives {
2693 const char *vendor;
2694 const char *model;
2695 unsigned short sparecyl;
2696 unsigned short ncyl;
2697 unsigned short nacyl;
2698 unsigned short pcylcount;
2699 unsigned short ntrks;
2700 unsigned short nsect;
2701 unsigned short rspeed;
2702} sun_drives[] = {
2703{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2704{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2705{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2706{"IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2707{"IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2708{"IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2709{"SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2710{"","SUN0104",1,974,2,1019,6,35,3662},
2711{"","SUN0207",4,1254,2,1272,9,36,3600},
2712{"","SUN0327",3,1545,2,1549,9,46,3600},
2713{"","SUN0340",0,1538,2,1544,6,72,4200},
2714{"","SUN0424",2,1151,2,2500,9,80,4400},
2715{"","SUN0535",0,1866,2,2500,7,80,5400},
2716{"","SUN0669",5,1614,2,1632,15,54,3600},
2717{"","SUN1.0G",5,1703,2,1931,15,80,3597},
2718{"","SUN1.05",0,2036,2,2038,14,72,5400},
2719{"","SUN1.3G",6,1965,2,3500,17,80,5400},
2720{"","SUN2.1G",0,2733,2,3500,19,80,5400},
2721{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
2722};
2723
2724static const struct sun_predefined_drives *
2725sun_autoconfigure_scsi(void) {
2726 const struct sun_predefined_drives *p = NULL;
2727
2728#ifdef SCSI_IOCTL_GET_IDLUN
2729 unsigned int id[2];
2730 char buffer[2048];
2731 char buffer2[2048];
2732 FILE *pfd;
2733 char *vendor;
2734 char *model;
2735 char *q;
2736 int i;
2737
2738 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2739 sprintf(buffer,
2740 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
2741#if 0
2742 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
2743#else
2744 /* This is very wrong (works only if you have one HBA),
2745 but I haven't found a way how to get hostno
2746 from the current kernel */
2747 0,
2748#endif
2749 (id[0]>>16)&0xff,
2750 id[0]&0xff,
2751 (id[0]>>8)&0xff);
2752 pfd = fopen("/proc/scsi/scsi","r");
2753 if (pfd) {
2754 while (fgets(buffer2,2048,pfd)) {
2755 if (!strcmp(buffer, buffer2)) {
2756 if (fgets(buffer2,2048,pfd)) {
2757 q = strstr(buffer2,"Vendor: ");
2758 if (q) {
2759 q += 8;
2760 vendor = q;
2761 q = strstr(q," ");
2762 *q++ = 0; /* truncate vendor name */
2763 q = strstr(q,"Model: ");
2764 if (q) {
2765 *q = 0;
2766 q += 7;
2767 model = q;
2768 q = strstr(q," Rev: ");
2769 if (q) {
2770 *q = 0;
2771 for (i = 0; i < SIZE(sun_drives); i++) {
2772 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2773 continue;
2774 if (!strstr(model, sun_drives[i].model))
2775 continue;
2776 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2777 p = sun_drives + i;
2778 break;
2779 }
2780 }
2781 }
2782 }
2783 }
2784 break;
2785 }
2786 }
2787 fclose(pfd);
2788 }
2789 }
2790#endif
2791 return p;
2792}
2793
2794static void create_sunlabel(void)
2795{
2796 struct hd_geometry geometry;
2797 unsigned int ndiv;
2798 int i;
2799 unsigned char c;
2800 const struct sun_predefined_drives *p = NULL;
2801
2802 fprintf(stderr,
2803 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2804 "until you decide to write them. After that, of course, the previous\n"
2805 "content won't be recoverable.\n\n"));
2806#if BYTE_ORDER == LITTLE_ENDIAN
2807 sun_other_endian = 1;
2808#else
2809 sun_other_endian = 0;
2810#endif
2811 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2812 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2813 if (!floppy) {
2814 puts(_("Drive type\n"
2815 " ? auto configure\n"
2816 " 0 custom (with hardware detected defaults)"));
2817 for (i = 0; i < SIZE(sun_drives); i++) {
2818 printf(" %c %s%s%s\n",
2819 i + 'a', sun_drives[i].vendor,
2820 (*sun_drives[i].vendor) ? " " : "",
2821 sun_drives[i].model);
2822 }
2823 for (;;) {
2824 c = read_char(_("Select type (? for auto, 0 for custom): "));
2825 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2826 p = sun_drives + c - 'a';
2827 break;
2828 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2829 p = sun_drives + c - 'A';
2830 break;
2831 } else if (c == '0') {
2832 break;
2833 } else if (c == '?' && scsi_disk) {
2834 p = sun_autoconfigure_scsi();
2835 if (!p)
2836 printf(_("Autoconfigure failed.\n"));
2837 else
2838 break;
2839 }
2840 }
2841 }
2842 if (!p || floppy) {
2843#ifdef HDIO_REQ
2844 if (!ioctl(fd, HDIO_REQ, &geometry)) {
2845#else
2846 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2847#endif
2848 heads = geometry.heads;
2849 sectors = geometry.sectors;
2850 cylinders = geometry.cylinders;
2851 } else {
2852 heads = 0;
2853 sectors = 0;
2854 cylinders = 0;
2855 }
2856 if (floppy) {
2857 sunlabel->nacyl = 0;
2858 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2859 sunlabel->rspeed = SUN_SSWAP16(300);
2860 sunlabel->ilfact = SUN_SSWAP16(1);
2861 sunlabel->sparecyl = 0;
2862 } else {
2863 heads = read_int(1,heads,1024,0,_("Heads"));
2864 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
2865 if (cylinders)
2866 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
2867 else
2868 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2869 sunlabel->nacyl =
2870 SUN_SSWAP16(read_int(0,2,65535,0,
2871 _("Alternate cylinders")));
2872 sunlabel->pcylcount =
2873 SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl),
2874 65535,0,_("Physical cylinders")));
2875 sunlabel->rspeed =
2876 SUN_SSWAP16(read_int(1,5400,100000,0,
2877 _("Rotation speed (rpm)")));
2878 sunlabel->ilfact =
2879 SUN_SSWAP16(read_int(1,1,32,0,_("Interleave factor")));
2880 sunlabel->sparecyl =
2881 SUN_SSWAP16(read_int(0,0,sectors,0,
2882 _("Extra sectors per cylinder")));
2883 }
2884 } else {
2885 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2886 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2887 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2888 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2889 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2890 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2891 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2892 sunlabel->ilfact = SUN_SSWAP16(1);
2893 cylinders = p->ncyl;
2894 heads = p->ntrks;
2895 sectors = p->nsect;
2896 puts(_("You may change all the disk params from the x menu"));
2897 }
2898
2899 snprintf(sunlabel->info, sizeof(sunlabel->info),
2900 "%s%s%s cyl %d alt %d hd %d sec %d",
2901 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2902 p ? p->model
2903 : (floppy ? _("3,5\" floppy") : _("Linux custom")),
2904 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2905
2906 sunlabel->ntrks = SUN_SSWAP16(heads);
2907 sunlabel->nsect = SUN_SSWAP16(sectors);
2908 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2909 if (floppy)
2910 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
2911 else {
2912 if (cylinders * heads * sectors >= 150 * 2048) {
2913 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2914 } else
2915 ndiv = cylinders * 2 / 3;
2916 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2917 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2918 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
2919 }
2920 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2921 {
2922 unsigned short *ush = (unsigned short *)sunlabel;
2923 unsigned short csum = 0;
2924 while(ush < (unsigned short *)(&sunlabel->csum))
2925 csum ^= *ush++;
2926 sunlabel->csum = csum;
2927 }
2928
2929 set_all_unchanged();
2930 set_changed(0);
2931 get_boot(create_empty_sun);
2932}
2933
2934static void
2935toggle_sunflags(int i, unsigned char mask) {
2936 if (sunlabel->infos[i].flags & mask)
2937 sunlabel->infos[i].flags &= ~mask;
2938 else sunlabel->infos[i].flags |= mask;
2939 set_changed(i);
2940}
2941
2942static void
2943fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) {
2944 int i, continuous = 1;
2945 *start = 0; *stop = cylinders * heads * sectors;
2946 for (i = 0; i < partitions; i++) {
2947 if (sunlabel->partitions[i].num_sectors
2948 && sunlabel->infos[i].id
2949 && sunlabel->infos[i].id != WHOLE_DISK) {
2950 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2951 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2952 if (continuous) {
2953 if (starts[i] == *start)
2954 *start += lens[i];
2955 else if (starts[i] + lens[i] >= *stop)
2956 *stop = starts[i];
2957 else
2958 continuous = 0;
2959 /* There will be probably more gaps
2960 than one, so lets check afterwards */
2961 }
2962 } else {
2963 starts[i] = 0;
2964 lens[i] = 0;
2965 }
2966 }
2967}
2968
2969static uint *verify_sun_starts;
2970
2971static int
2972verify_sun_cmp(int *a, int *b) {
2973 if (*a == -1) return 1;
2974 if (*b == -1) return -1;
2975 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2976 return -1;
2977}
2978
2979static void
2980verify_sun(void) {
2981 uint starts[8], lens[8], start, stop;
2982 int i,j,k,starto,endo;
2983 int array[8];
2984
2985 verify_sun_starts = starts;
2986 fetch_sun(starts,lens,&start,&stop);
2987 for (k = 0; k < 7; k++) {
2988 for (i = 0; i < 8; i++) {
2989 if (k && (lens[i] % (heads * sectors))) {
2990 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
2991 }
2992 if (lens[i]) {
2993 for (j = 0; j < i; j++)
2994 if (lens[j]) {
2995 if (starts[j] == starts[i]+lens[i]) {
2996 starts[j] = starts[i]; lens[j] += lens[i];
2997 lens[i] = 0;
2998 } else if (starts[i] == starts[j]+lens[j]){
2999 lens[j] += lens[i];
3000 lens[i] = 0;
3001 } else if (!k) {
3002 if (starts[i] < starts[j]+lens[j] &&
3003 starts[j] < starts[i]+lens[i]) {
3004 starto = starts[i];
3005 if (starts[j] > starto)
3006 starto = starts[j];
3007 endo = starts[i]+lens[i];
3008 if (starts[j]+lens[j] < endo)
3009 endo = starts[j]+lens[j];
3010 printf(_("Partition %d overlaps with others in "
3011 "sectors %d-%d\n"), i+1, starto, endo);
3012 }
3013 }
3014 }
3015 }
3016 }
3017 }
3018 for (i = 0; i < 8; i++) {
3019 if (lens[i])
3020 array[i] = i;
3021 else
3022 array[i] = -1;
3023 }
3024 qsort(array,SIZE(array),sizeof(array[0]),
3025 (int (*)(const void *,const void *)) verify_sun_cmp);
3026 if (array[0] == -1) {
3027 printf(_("No partitions defined\n"));
3028 return;
3029 }
3030 stop = cylinders * heads * sectors;
3031 if (starts[array[0]])
3032 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
3033 for (i = 0; i < 7 && array[i+1] != -1; i++) {
3034 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
3035 }
3036 start = starts[array[i]]+lens[array[i]];
3037 if (start < stop)
3038 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
3039}
3040
3041static void
3042add_sun_partition(int n, int sys) {
3043 uint start, stop, stop2;
3044 uint starts[8], lens[8];
3045 int whole_disk = 0;
3046
3047 char mesg[256];
3048 int i, first, last;
3049
3050 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
3051 printf(_("Partition %d is already defined. Delete "
3052 "it before re-adding it.\n"), n + 1);
3053 return;
3054 }
3055
3056 fetch_sun(starts,lens,&start,&stop);
3057 if (stop <= start) {
3058 if (n == 2)
3059 whole_disk = 1;
3060 else {
3061 printf(_("Other partitions already cover the whole disk.\nDelete "
3062 "some/shrink them before retry.\n"));
3063 return;
3064 }
3065 }
3066 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
3067 for (;;) {
3068 if (whole_disk)
3069 first = read_int(0, 0, 0, 0, mesg);
3070 else
3071 first = read_int(scround(start), scround(stop)+1,
3072 scround(stop), 0, mesg);
3073 if (display_in_cyl_units)
3074 first *= units_per_sector;
3075 else
3076 /* Starting sector has to be properly aligned */
3077 first = (first + heads * sectors - 1) / (heads * sectors);
3078 if (n == 2 && first != 0)
3079 printf ("\
3080It is highly recommended that the third partition covers the whole disk\n\
3081and is of type `Whole disk'\n");
3082 /* ewt asks to add: "don't start a partition at cyl 0"
3083 However, edmundo@rano.demon.co.uk writes:
3084 "In addition to having a Sun partition table, to be able to
3085 boot from the disc, the first partition, /dev/sdX1, must
3086 start at cylinder 0. This means that /dev/sdX1 contains
3087 the partition table and the boot block, as these are the
3088 first two sectors of the disc. Therefore you must be
3089 careful what you use /dev/sdX1 for. In particular, you must
3090 not use a partition starting at cylinder 0 for Linux swap,
3091 as that would overwrite the partition table and the boot
3092 block. You may, however, use such a partition for a UFS
3093 or EXT2 file system, as these file systems leave the first
3094 1024 bytes undisturbed. */
3095 /* On the other hand, one should not use partitions
3096 starting at block 0 in an md, or the label will
3097 be trashed. */
3098 for (i = 0; i < partitions; i++)
3099 if (lens[i] && starts[i] <= first
3100 && starts[i] + lens[i] > first)
3101 break;
3102 if (i < partitions && !whole_disk) {
3103 if (n == 2 && !first) {
3104 whole_disk = 1;
3105 break;
3106 }
3107 printf(_("Sector %d is already allocated\n"), first);
3108 } else
3109 break;
3110 }
3111 stop = cylinders * heads * sectors;
3112 stop2 = stop;
3113 for (i = 0; i < partitions; i++) {
3114 if (starts[i] > first && starts[i] < stop)
3115 stop = starts[i];
3116 }
3117 snprintf(mesg, sizeof(mesg),
3118 _("Last %s or +size or +sizeM or +sizeK"),
3119 str_units(SINGULAR));
3120 if (whole_disk)
3121 last = read_int(scround(stop2), scround(stop2), scround(stop2),
3122 0, mesg);
3123 else if (n == 2 && !first)
3124 last = read_int(scround(first), scround(stop2), scround(stop2),
3125 scround(first), mesg);
3126 else
3127 last = read_int(scround(first), scround(stop), scround(stop),
3128 scround(first), mesg);
3129 if (display_in_cyl_units)
3130 last *= units_per_sector;
3131 if (n == 2 && !first) {
3132 if (last >= stop2) {
3133 whole_disk = 1;
3134 last = stop2;
3135 } else if (last > stop) {
3136 printf (
3137 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
3138 "%d %s covers some other partition. Your entry has been changed\n"
3139 "to %d %s\n"),
3140 scround(last), str_units(SINGULAR),
3141 scround(stop), str_units(SINGULAR));
3142 last = stop;
3143 }
3144 } else if (!whole_disk && last > stop)
3145 last = stop;
3146
3147 if (whole_disk) sys = WHOLE_DISK;
3148 set_sun_partition(n, first, last, sys);
3149}
3150
3151static void
3152sun_delete_partition(int i) {
3153 if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
3154 !sunlabel->partitions[i].start_cylinder &&
3155 SUN_SSWAP32(sunlabel->partitions[i].num_sectors)
3156 == heads * sectors * cylinders)
3157 printf(_("If you want to maintain SunOS/Solaris compatibility, "
3158 "consider leaving this\n"
3159 "partition as Whole disk (5), starting at 0, with %u "
3160 "sectors\n"),
3161 (uint) SUN_SSWAP32(sunlabel->partitions[i].num_sectors));
3162 sunlabel->infos[i].id = 0;
3163 sunlabel->partitions[i].num_sectors = 0;
3164}
3165
3166static void
3167sun_change_sysid(int i, int sys) {
3168 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
3169 read_chars(
3170 _("It is highly recommended that the partition at offset 0\n"
3171 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3172 "there may destroy your partition table and bootblock.\n"
3173 "Type YES if you're very sure you would like that partition\n"
3174 "tagged with 82 (Linux swap): "));
3175 if (strcmp (line_ptr, _("YES\n")))
3176 return;
3177 }
3178 switch (sys) {
3179 case SUNOS_SWAP:
3180 case LINUX_SWAP:
3181 /* swaps are not mountable by default */
3182 sunlabel->infos[i].flags |= 0x01;
3183 break;
3184 default:
3185 /* assume other types are mountable;
3186 user can change it anyway */
3187 sunlabel->infos[i].flags &= ~0x01;
3188 break;
3189 }
3190 sunlabel->infos[i].id = sys;
3191}
3192
3193static void
3194sun_list_table(int xtra) {
3195 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003196
3197 w = strlen(disk_device);
3198 if (xtra)
3199 printf(
3200 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3201 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3202 "%d extra sects/cyl, interleave %d:1\n"
3203 "%s\n"
3204 "Units = %s of %d * 512 bytes\n\n"),
3205 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3206 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3207 SUN_SSWAP16(sunlabel->pcylcount),
3208 SUN_SSWAP16(sunlabel->sparecyl),
3209 SUN_SSWAP16(sunlabel->ilfact),
3210 (char *)sunlabel,
3211 str_units(PLURAL), units_per_sector);
3212 else
3213 printf(
3214 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3215 "Units = %s of %d * 512 bytes\n\n"),
3216 disk_device, heads, sectors, cylinders,
3217 str_units(PLURAL), units_per_sector);
3218
3219 printf(_("%*s Flag Start End Blocks Id System\n"),
3220 w + 1, _("Device"));
3221 for (i = 0 ; i < partitions; i++) {
3222 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003223 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3224 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003225 printf(
3226 "%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3227/* device */ partname(disk_device, i+1, w),
3228/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
3229 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3230/* start */ (long) scround(start),
3231/* end */ (long) scround(start+len),
3232/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
3233/* type id */ sunlabel->infos[i].id,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003234/* type name */ partition_type(sunlabel->infos[i].id));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003235 }
3236 }
3237}
3238
3239static void
3240sun_set_alt_cyl(void) {
3241 sunlabel->nacyl =
3242 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
3243 _("Number of alternate cylinders")));
3244}
3245
3246static void
3247sun_set_ncyl(int cyl) {
3248 sunlabel->ncyl = SUN_SSWAP16(cyl);
3249}
3250
3251static void
3252sun_set_xcyl(void) {
3253 sunlabel->sparecyl =
3254 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
3255 _("Extra sectors per cylinder")));
3256}
3257
3258static void
3259sun_set_ilfact(void) {
3260 sunlabel->ilfact =
3261 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
3262 _("Interleave factor")));
3263}
3264
3265static void
3266sun_set_rspeed(void) {
3267 sunlabel->rspeed =
3268 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
3269 _("Rotation speed (rpm)")));
3270}
3271
3272static void
3273sun_set_pcylcount(void) {
3274 sunlabel->pcylcount =
3275 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
3276 _("Number of physical cylinders")));
3277}
3278
3279static void
3280sun_write_table(void) {
3281 unsigned short *ush = (unsigned short *)sunlabel;
3282 unsigned short csum = 0;
3283
3284 while(ush < (unsigned short *)(&sunlabel->csum))
3285 csum ^= *ush++;
3286 sunlabel->csum = csum;
3287 if (lseek(fd, 0, SEEK_SET) < 0)
3288 fdisk_fatal(unable_to_seek);
3289 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3290 fdisk_fatal(unable_to_write);
3291}
3292#endif /* SUN_LABEL */
3293
3294/* DOS partition types */
3295
3296static const struct systypes i386_sys_types[] = {
3297 {"\x00" "Empty"},
3298 {"\x01" "FAT12"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003299 {"\x04" "FAT16 <32M"},
3300 {"\x05" "Extended"}, /* DOS 3.3+ extended partition */
3301 {"\x06" "FAT16"}, /* DOS 16-bit >=32M */
3302 {"\x07" "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003303 {"\x0a" "OS/2 Boot Manager"},/* OS/2 Boot Manager */
3304 {"\x0b" "Win95 FAT32"},
3305 {"\x0c" "Win95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
3306 {"\x0e" "Win95 FAT16 (LBA)"},
3307 {"\x0f" "Win95 Ext'd (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003308 {"\x11" "Hidden FAT12"},
3309 {"\x12" "Compaq diagnostics"},
3310 {"\x14" "Hidden FAT16 <32M"},
3311 {"\x16" "Hidden FAT16"},
3312 {"\x17" "Hidden HPFS/NTFS"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003313 {"\x1b" "Hidden Win95 FAT32"},
3314 {"\x1c" "Hidden Win95 FAT32 (LBA)"},
3315 {"\x1e" "Hidden Win95 FAT16 (LBA)"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003316 {"\x3c" "PartitionMagic recovery"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003317 {"\x41" "PPC PReP Boot"},
3318 {"\x42" "SFS"},
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003319 {"\x63" "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3320 {"\x80" "Old Minix"}, /* Minix 1.4a and earlier */
3321 {"\x81" "Minix / old Linux"},/* Minix 1.4b and later */
3322 {"\x82" "Linux swap"}, /* also Solaris */
3323 {"\x83" "Linux"},
3324 {"\x84" "OS/2 hidden C: drive"},
3325 {"\x85" "Linux extended"},
3326 {"\x86" "NTFS volume set"},
3327 {"\x87" "NTFS volume set"},
3328 {"\x8e" "Linux LVM"},
3329 {"\x9f" "BSD/OS"}, /* BSDI */
3330 {"\xa0" "IBM Thinkpad hibernation"},
3331 {"\xa5" "FreeBSD"}, /* various BSD flavours */
3332 {"\xa6" "OpenBSD"},
3333 {"\xa8" "Darwin UFS"},
3334 {"\xa9" "NetBSD"},
3335 {"\xab" "Darwin boot"},
3336 {"\xb7" "BSDI fs"},
3337 {"\xb8" "BSDI swap"},
3338 {"\xbe" "Solaris boot"},
3339 {"\xeb" "BeOS fs"},
3340 {"\xee" "EFI GPT"}, /* Intel EFI GUID Partition Table */
3341 {"\xef" "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
3342 {"\xf0" "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
3343 {"\xf2" "DOS secondary"}, /* DOS 3.3+ secondary */
3344 {"\xfd" "Linux raid autodetect"},/* New (2.2.x) raid partition with
3345 autodetect using persistent
3346 superblock */
3347#ifdef CONFIG_WEIRD_PARTITION_TYPES
3348 {"\x02" "XENIX root"},
3349 {"\x03" "XENIX usr"},
3350 {"\x08" "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3351 {"\x09" "AIX bootable"}, /* AIX data or Coherent */
3352 {"\x10" "OPUS"},
3353 {"\x18" "AST SmartSleep"},
3354 {"\x24" "NEC DOS"},
3355 {"\x39" "Plan 9"},
3356 {"\x40" "Venix 80286"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003357 {"\x4d" "QNX4.x"},
3358 {"\x4e" "QNX4.x 2nd part"},
3359 {"\x4f" "QNX4.x 3rd part"},
3360 {"\x50" "OnTrack DM"},
3361 {"\x51" "OnTrack DM6 Aux1"}, /* (or Novell) */
3362 {"\x52" "CP/M"}, /* CP/M or Microport SysV/AT */
3363 {"\x53" "OnTrack DM6 Aux3"},
3364 {"\x54" "OnTrackDM6"},
3365 {"\x55" "EZ-Drive"},
3366 {"\x56" "Golden Bow"},
3367 {"\x5c" "Priam Edisk"},
3368 {"\x61" "SpeedStor"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003369 {"\x64" "Novell Netware 286"},
3370 {"\x65" "Novell Netware 386"},
3371 {"\x70" "DiskSecure Multi-Boot"},
3372 {"\x75" "PC/IX"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003373 {"\x93" "Amoeba"},
3374 {"\x94" "Amoeba BBT"}, /* (bad block table) */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003375 {"\xa7" "NeXTSTEP"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003376 {"\xbb" "Boot Wizard hidden"},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003377 {"\xc1" "DRDOS/sec (FAT-12)"},
3378 {"\xc4" "DRDOS/sec (FAT-16 < 32M)"},
3379 {"\xc6" "DRDOS/sec (FAT-16)"},
3380 {"\xc7" "Syrinx"},
3381 {"\xda" "Non-FS data"},
3382 {"\xdb" "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
3383 Concurrent DOS or CTOS */
3384 {"\xde" "Dell Utility"}, /* Dell PowerEdge Server utilities */
3385 {"\xdf" "BootIt"}, /* BootIt EMBRM */
3386 {"\xe1" "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
3387 extended partition */
3388 {"\xe3" "DOS R/O"}, /* DOS R/O or SpeedStor */
3389 {"\xe4" "SpeedStor"}, /* SpeedStor 16-bit FAT extended
3390 partition < 1024 cyl. */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003391 {"\xf1" "SpeedStor"},
3392 {"\xf4" "SpeedStor"}, /* SpeedStor large partition */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003393 {"\xfe" "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
3394 {"\xff" "BBT"}, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003395#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003396 { 0 }
3397};
3398
3399
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003400
3401/* A valid partition table sector ends in 0x55 0xaa */
3402static unsigned int
3403part_table_flag(const char *b) {
3404 return ((uint) b[510]) + (((uint) b[511]) << 8);
3405}
3406
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003407
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003408#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003409static void
3410write_part_table_flag(char *b) {
3411 b[510] = 0x55;
3412 b[511] = 0xaa;
3413}
3414
3415/* start_sect and nr_sects are stored little endian on all machines */
3416/* moreover, they are not aligned correctly */
3417static void
3418store4_little_endian(unsigned char *cp, unsigned int val) {
3419 cp[0] = (val & 0xff);
3420 cp[1] = ((val >> 8) & 0xff);
3421 cp[2] = ((val >> 16) & 0xff);
3422 cp[3] = ((val >> 24) & 0xff);
3423}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003424#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003425
3426static unsigned int
3427read4_little_endian(const unsigned char *cp) {
3428 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3429 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3430}
3431
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003432#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003433static void
3434set_start_sect(struct partition *p, unsigned int start_sect) {
3435 store4_little_endian(p->start4, start_sect);
3436}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003437#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003438
3439static unsigned int
3440get_start_sect(const struct partition *p) {
3441 return read4_little_endian(p->start4);
3442}
3443
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003444#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003445static void
3446set_nr_sects(struct partition *p, unsigned int nr_sects) {
3447 store4_little_endian(p->size4, nr_sects);
3448}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003449#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003450
3451static unsigned int
3452get_nr_sects(const struct partition *p) {
3453 return read4_little_endian(p->size4);
3454}
3455
3456/* normally O_RDWR, -l option gives O_RDONLY */
3457static int type_open = O_RDWR;
3458
3459
3460static int ext_index, /* the prime extended partition */
3461 listing, /* no aborts for fdisk -l */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003462 dos_compatible_flag = ~0;
3463#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3464static int dos_changed;
3465static int nowarn; /* no warnings for fdisk -l/-s */
3466#endif
3467
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003468
3469
3470static uint user_cylinders, user_heads, user_sectors;
3471static uint pt_heads, pt_sectors;
3472static uint kern_heads, kern_sectors;
3473
3474static uint extended_offset; /* offset of link pointers */
3475static uint sector_size = DEFAULT_SECTOR_SIZE,
3476 user_set_sector_size,
3477 sector_offset = 1;
3478
3479static unsigned long total_number_of_sectors;
3480
3481
3482static jmp_buf listingbuf;
3483
3484static void fdisk_fatal(enum failure why) {
3485 const char *message;
3486
3487 if (listing) {
3488 close(fd);
3489 longjmp(listingbuf, 1);
3490 }
3491
3492 switch (why) {
3493 case unable_to_open:
3494 message = "Unable to open %s\n";
3495 break;
3496 case unable_to_read:
3497 message = "Unable to read %s\n";
3498 break;
3499 case unable_to_seek:
3500 message = "Unable to seek on %s\n";
3501 break;
3502 case unable_to_write:
3503 message = "Unable to write %s\n";
3504 break;
3505 case ioctl_error:
3506 message = "BLKGETSIZE ioctl failed on %s\n";
3507 break;
3508 default:
3509 message = "Fatal error\n";
3510 }
3511
3512 fputc('\n', stderr);
3513 fprintf(stderr, message, disk_device);
3514 exit(1);
3515}
3516
3517static void
3518seek_sector(uint secno) {
3519 ext2_loff_t offset = (ext2_loff_t) secno * sector_size;
3520 if (ext2_llseek(fd, offset, SEEK_SET) == (ext2_loff_t) -1)
3521 fdisk_fatal(unable_to_seek);
3522}
3523
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003524#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003525static void
3526write_sector(uint secno, char *buf) {
3527 seek_sector(secno);
3528 if (write(fd, buf, sector_size) != sector_size)
3529 fdisk_fatal(unable_to_write);
3530}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003531#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003532
3533/* Allocate a buffer and read a partition table sector */
3534static void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003535read_pte(struct pte *pe, uint offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003536
3537 pe->offset = offset;
3538 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003539 seek_sector(offset);
3540 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3541 fdisk_fatal(unable_to_read);
3542#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003543 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003544#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003545 pe->part_table = pe->ext_pointer = NULL;
3546}
3547
3548static unsigned int
3549get_partition_start(const struct pte *pe) {
3550 return pe->offset + get_start_sect(pe->part_table);
3551}
3552
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003553#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003554/*
3555 * Avoid warning about DOS partitions when no DOS partition was changed.
3556 * Here a heuristic "is probably dos partition".
3557 * We might also do the opposite and warn in all cases except
3558 * for "is probably nondos partition".
3559 */
3560static int
3561is_dos_partition(int t) {
3562 return (t == 1 || t == 4 || t == 6 ||
3563 t == 0x0b || t == 0x0c || t == 0x0e ||
3564 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3565 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3566 t == 0xc1 || t == 0xc4 || t == 0xc6);
3567}
3568
3569static void
3570menu(void) {
3571#ifdef CONFIG_FEATURE_SUN_LABEL
3572 if (sun_label) {
3573 puts(_("Command action"));
3574 puts(_("\ta\ttoggle a read only flag")); /* sun */
3575 puts(_("\tb\tedit bsd disklabel"));
3576 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3577 puts(_("\td\tdelete a partition"));
3578 puts(_("\tl\tlist known partition types"));
3579 puts(_("\tm\tprint this menu"));
3580 puts(_("\tn\tadd a new partition"));
3581 puts(_("\to\tcreate a new empty DOS partition table"));
3582 puts(_("\tp\tprint the partition table"));
3583 puts(_("\tq\tquit without saving changes"));
3584 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3585 puts(_("\tt\tchange a partition's system id"));
3586 puts(_("\tu\tchange display/entry units"));
3587 puts(_("\tv\tverify the partition table"));
3588 puts(_("\tw\twrite table to disk and exit"));
3589#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3590 puts(_("\tx\textra functionality (experts only)"));
3591#endif
3592 } else
3593#endif
3594#ifdef CONFIG_FEATURE_SGI_LABEL
3595 if (sgi_label) {
3596 puts(_("Command action"));
3597 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3598 puts(_("\tb\tedit bootfile entry")); /* sgi */
3599 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3600 puts(_("\td\tdelete a partition"));
3601 puts(_("\tl\tlist known partition types"));
3602 puts(_("\tm\tprint this menu"));
3603 puts(_("\tn\tadd a new partition"));
3604 puts(_("\to\tcreate a new empty DOS partition table"));
3605 puts(_("\tp\tprint the partition table"));
3606 puts(_("\tq\tquit without saving changes"));
3607 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3608 puts(_("\tt\tchange a partition's system id"));
3609 puts(_("\tu\tchange display/entry units"));
3610 puts(_("\tv\tverify the partition table"));
3611 puts(_("\tw\twrite table to disk and exit"));
3612 } else
3613#endif
3614#ifdef CONFIG_FEATURE_AIX_LABEL
3615 if (aix_label) {
3616 puts(_("Command action"));
3617 puts(_("\tm\tprint this menu"));
3618 puts(_("\to\tcreate a new empty DOS partition table"));
3619 puts(_("\tq\tquit without saving changes"));
3620 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3621 } else
3622#endif
3623 {
3624 puts(_("Command action"));
3625 puts(_("\ta\ttoggle a bootable flag"));
3626 puts(_("\tb\tedit bsd disklabel"));
3627 puts(_("\tc\ttoggle the dos compatibility flag"));
3628 puts(_("\td\tdelete a partition"));
3629 puts(_("\tl\tlist known partition types"));
3630 puts(_("\tm\tprint this menu"));
3631 puts(_("\tn\tadd a new partition"));
3632 puts(_("\to\tcreate a new empty DOS partition table"));
3633 puts(_("\tp\tprint the partition table"));
3634 puts(_("\tq\tquit without saving changes"));
3635 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3636 puts(_("\tt\tchange a partition's system id"));
3637 puts(_("\tu\tchange display/entry units"));
3638 puts(_("\tv\tverify the partition table"));
3639 puts(_("\tw\twrite table to disk and exit"));
3640#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3641 puts(_("\tx\textra functionality (experts only)"));
3642#endif
3643 }
3644}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003645#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3646
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003647
3648#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3649static void
3650xmenu(void) {
3651#ifdef CONFIG_FEATURE_SUN_LABEL
3652 if (sun_label) {
3653 puts(_("Command action"));
3654 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3655 puts(_("\tc\tchange number of cylinders"));
3656 puts(_("\td\tprint the raw data in the partition table"));
3657 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3658 puts(_("\th\tchange number of heads"));
3659 puts(_("\ti\tchange interleave factor")); /*sun*/
3660 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3661 puts(_("\tm\tprint this menu"));
3662 puts(_("\tp\tprint the partition table"));
3663 puts(_("\tq\tquit without saving changes"));
3664 puts(_("\tr\treturn to main menu"));
3665 puts(_("\ts\tchange number of sectors/track"));
3666 puts(_("\tv\tverify the partition table"));
3667 puts(_("\tw\twrite table to disk and exit"));
3668 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
3669 } else
3670#endif
3671#ifdef CONFIG_FEATURE_SGI_LABEL
3672 if (sgi_label) {
3673 puts(_("Command action"));
3674 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3675 puts(_("\tc\tchange number of cylinders"));
3676 puts(_("\td\tprint the raw data in the partition table"));
3677 puts(_("\te\tlist extended partitions")); /* !sun */
3678 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3679 puts(_("\th\tchange number of heads"));
3680 puts(_("\tm\tprint this menu"));
3681 puts(_("\tp\tprint the partition table"));
3682 puts(_("\tq\tquit without saving changes"));
3683 puts(_("\tr\treturn to main menu"));
3684 puts(_("\ts\tchange number of sectors/track"));
3685 puts(_("\tv\tverify the partition table"));
3686 puts(_("\tw\twrite table to disk and exit"));
3687 } else
3688#endif
3689#ifdef CONFIG_FEATURE_AIX_LABEL
3690 if (aix_label) {
3691 puts(_("Command action"));
3692 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3693 puts(_("\tc\tchange number of cylinders"));
3694 puts(_("\td\tprint the raw data in the partition table"));
3695 puts(_("\te\tlist extended partitions")); /* !sun */
3696 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3697 puts(_("\th\tchange number of heads"));
3698 puts(_("\tm\tprint this menu"));
3699 puts(_("\tp\tprint the partition table"));
3700 puts(_("\tq\tquit without saving changes"));
3701 puts(_("\tr\treturn to main menu"));
3702 puts(_("\ts\tchange number of sectors/track"));
3703 puts(_("\tv\tverify the partition table"));
3704 puts(_("\tw\twrite table to disk and exit"));
3705 } else
3706#endif
3707 {
3708 puts(_("Command action"));
3709 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3710 puts(_("\tc\tchange number of cylinders"));
3711 puts(_("\td\tprint the raw data in the partition table"));
3712 puts(_("\te\tlist extended partitions")); /* !sun */
3713 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
3714#ifdef CONFIG_FEATURE_SGI_LABEL
3715 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3716#endif
3717 puts(_("\th\tchange number of heads"));
3718 puts(_("\tm\tprint this menu"));
3719 puts(_("\tp\tprint the partition table"));
3720 puts(_("\tq\tquit without saving changes"));
3721 puts(_("\tr\treturn to main menu"));
3722 puts(_("\ts\tchange number of sectors/track"));
3723 puts(_("\tv\tverify the partition table"));
3724 puts(_("\tw\twrite table to disk and exit"));
3725 }
3726}
3727#endif /* ADVANCED mode */
3728
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003729#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003730static const struct systypes *
3731get_sys_types(void) {
3732 return (
3733#ifdef CONFIG_FEATURE_SUN_LABEL
3734 sun_label ? sun_sys_types :
3735#endif
3736#ifdef CONFIG_FEATURE_SGI_LABEL
3737 sgi_label ? sgi_sys_types :
3738#endif
3739 i386_sys_types);
3740}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003741#else
3742#define get_sys_types() i386_sys_types
3743#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003744
3745static const char *partition_type(unsigned char type)
3746{
3747 int i;
3748 const struct systypes *types = get_sys_types();
3749
3750 for (i=0; types[i].name; i++)
3751 if (types[i].name[0] == type)
3752 return types[i].name + 1;
3753
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003754 return _("Unknown");
3755}
3756
3757
3758#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3759static int
3760get_sysid(int i) {
3761 return (
3762#ifdef CONFIG_FEATURE_SUN_LABEL
3763 sun_label ? sunlabel->infos[i].id :
3764#endif
3765#ifdef CONFIG_FEATURE_SGI_LABEL
3766 sgi_label ? sgi_get_sysid(i) :
3767#endif
3768 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003769}
3770
3771void list_types(const struct systypes *sys)
3772{
3773 uint last[4], done = 0, next = 0, size;
3774 int i;
3775
3776 for (i = 0; sys[i].name; i++);
3777 size = i;
3778
3779 for (i = 3; i >= 0; i--)
3780 last[3 - i] = done += (size + i - done) / (i + 1);
3781 i = done = 0;
3782
3783 do {
3784 printf("%c%2x %-15.15s", i ? ' ' : '\n',
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003785 sys[next].name[0], partition_type(sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003786 next = last[i++] + done;
3787 if (i > 3 || next >= last[i]) {
3788 i = 0;
3789 next = ++done;
3790 }
3791 } while (done < last[0]);
3792 putchar('\n');
3793}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003794#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003795
3796static int
3797is_cleared_partition(const struct partition *p) {
3798 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3799 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3800 get_start_sect(p) || get_nr_sects(p));
3801}
3802
3803static void
3804clear_partition(struct partition *p) {
3805 if (!p)
3806 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003807 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003808}
3809
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003810#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003811static void
3812set_partition(int i, int doext, uint start, uint stop, int sysid) {
3813 struct partition *p;
3814 uint offset;
3815
3816 if (doext) {
3817 p = ptes[i].ext_pointer;
3818 offset = extended_offset;
3819 } else {
3820 p = ptes[i].part_table;
3821 offset = ptes[i].offset;
3822 }
3823 p->boot_ind = 0;
3824 p->sys_ind = sysid;
3825 set_start_sect(p, start - offset);
3826 set_nr_sects(p, stop - start + 1);
3827 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3828 start = heads*sectors*1024 - 1;
3829 set_hsc(p->head, p->sector, p->cyl, start);
3830 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3831 stop = heads*sectors*1024 - 1;
3832 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3833 ptes[i].changed = 1;
3834}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003835#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003836
3837static int
3838test_c(const char **m, const char *mesg) {
3839 int val = 0;
3840 if (!*m)
3841 fprintf(stderr, _("You must set"));
3842 else {
3843 fprintf(stderr, " %s", *m);
3844 val = 1;
3845 }
3846 *m = mesg;
3847 return val;
3848}
3849
3850static int
3851warn_geometry(void) {
3852 const char *m = NULL;
3853 int prev = 0;
3854
3855 if (!heads)
3856 prev = test_c(&m, _("heads"));
3857 if (!sectors)
3858 prev = test_c(&m, _("sectors"));
3859 if (!cylinders)
3860 prev = test_c(&m, _("cylinders"));
3861 if (!m)
3862 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003863
3864 fprintf(stderr, "%s%s.\n"
3865#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3866 "You can do this from the extra functions menu.\n"
3867#endif
3868 , prev ? _(" and ") : " ", m);
3869
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003870 return 1;
3871}
3872
3873static void update_units(void)
3874{
3875 int cyl_units = heads * sectors;
3876
3877 if (display_in_cyl_units && cyl_units)
3878 units_per_sector = cyl_units;
3879 else
3880 units_per_sector = 1; /* in sectors */
3881}
3882
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003883#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003884static void
3885warn_cylinders(void) {
3886 if (dos_label && cylinders > 1024 && !nowarn)
3887 fprintf(stderr, _("\n"
3888"The number of cylinders for this disk is set to %d.\n"
3889"There is nothing wrong with that, but this is larger than 1024,\n"
3890"and could in certain setups cause problems with:\n"
3891"1) software that runs at boot time (e.g., old versions of LILO)\n"
3892"2) booting and partitioning software from other OSs\n"
3893" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3894 cylinders);
3895}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003896#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003897
3898static void
3899read_extended(int ext) {
3900 int i;
3901 struct pte *pex;
3902 struct partition *p, *q;
3903
3904 ext_index = ext;
3905 pex = &ptes[ext];
3906 pex->ext_pointer = pex->part_table;
3907
3908 p = pex->part_table;
3909 if (!get_start_sect(p)) {
3910 fprintf(stderr,
3911 _("Bad offset in primary extended partition\n"));
3912 return;
3913 }
3914
3915 while (IS_EXTENDED (p->sys_ind)) {
3916 struct pte *pe = &ptes[partitions];
3917
3918 if (partitions >= MAXIMUM_PARTS) {
3919 /* This is not a Linux restriction, but
3920 this program uses arrays of size MAXIMUM_PARTS.
3921 Do not try to `improve' this test. */
3922 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003923#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003924 fprintf(stderr,
3925 _("Warning: deleting partitions after %d\n"),
3926 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003927 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003928#endif
3929 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003930 return;
3931 }
3932
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003933 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003934
3935 if (!extended_offset)
3936 extended_offset = get_start_sect(p);
3937
3938 q = p = pt_offset(pe->sectorbuffer, 0);
3939 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
3940 if (IS_EXTENDED (p->sys_ind)) {
3941 if (pe->ext_pointer)
3942 fprintf(stderr,
3943 _("Warning: extra link "
3944 "pointer in partition table"
3945 " %d\n"), partitions + 1);
3946 else
3947 pe->ext_pointer = p;
3948 } else if (p->sys_ind) {
3949 if (pe->part_table)
3950 fprintf(stderr,
3951 _("Warning: ignoring extra "
3952 "data in partition table"
3953 " %d\n"), partitions + 1);
3954 else
3955 pe->part_table = p;
3956 }
3957 }
3958
3959 /* very strange code here... */
3960 if (!pe->part_table) {
3961 if (q != pe->ext_pointer)
3962 pe->part_table = q;
3963 else
3964 pe->part_table = q + 1;
3965 }
3966 if (!pe->ext_pointer) {
3967 if (q != pe->part_table)
3968 pe->ext_pointer = q;
3969 else
3970 pe->ext_pointer = q + 1;
3971 }
3972
3973 p = pe->ext_pointer;
3974 partitions++;
3975 }
3976
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003977#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003978 /* remove empty links */
3979 remove:
3980 for (i = 4; i < partitions; i++) {
3981 struct pte *pe = &ptes[i];
3982
3983 if (!get_nr_sects(pe->part_table) &&
3984 (partitions > 5 || ptes[4].part_table->sys_ind)) {
3985 printf("omitting empty partition (%d)\n", i+1);
3986 delete_partition(i);
3987 goto remove; /* numbering changed */
3988 }
3989 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003990#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003991}
3992
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003993#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003994static void
3995create_doslabel(void) {
3996 int i;
3997
3998 fprintf(stderr,
3999 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
4000 "until you decide to write them. After that, of course, the previous\n"
4001 "content won't be recoverable.\n\n"));
4002#ifdef CONFIG_FEATURE_SUN_LABEL
4003 sun_nolabel(); /* otherwise always recognised as sun */
4004#endif
4005#ifdef CONFIG_FEATURE_SGI_LABEL
4006 sgi_nolabel(); /* otherwise always recognised as sgi */
4007#endif
4008#ifdef CONFIG_FEATURE_AIX_LABEL
4009 aix_label = 0;
4010#endif
4011#ifdef CONFIG_FEATURE_OSF_LABEL
4012 osf_label = 0;
4013 possibly_osf_label = 0;
4014#endif
4015 partitions = 4;
4016
4017 for (i = 510-64; i < 510; i++)
4018 MBRbuffer[i] = 0;
4019 write_part_table_flag(MBRbuffer);
4020 extended_offset = 0;
4021 set_all_unchanged();
4022 set_changed(0);
4023 get_boot(create_empty_dos);
4024}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004025#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004026
4027static void
4028get_sectorsize(void) {
4029 if (!user_set_sector_size &&
4030 get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
4031 int arg;
4032 if (ioctl(fd, BLKSSZGET, &arg) == 0)
4033 sector_size = arg;
4034 if (sector_size != DEFAULT_SECTOR_SIZE)
4035 printf(_("Note: sector size is %d (not %d)\n"),
4036 sector_size, DEFAULT_SECTOR_SIZE);
4037 }
4038}
4039
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004040static inline void
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004041get_kernel_geometry(void) {
4042 struct hd_geometry geometry;
4043
4044 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
4045 kern_heads = geometry.heads;
4046 kern_sectors = geometry.sectors;
4047 /* never use geometry.cylinders - it is truncated */
4048 }
4049}
4050
4051static void
4052get_partition_table_geometry(void) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004053 const unsigned char *bufp = MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004054 struct partition *p;
4055 int i, h, s, hh, ss;
4056 int first = 1;
4057 int bad = 0;
4058
4059 if (!(valid_part_table_flag(bufp)))
4060 return;
4061
4062 hh = ss = 0;
4063 for (i=0; i<4; i++) {
4064 p = pt_offset(bufp, i);
4065 if (p->sys_ind != 0) {
4066 h = p->end_head + 1;
4067 s = (p->end_sector & 077);
4068 if (first) {
4069 hh = h;
4070 ss = s;
4071 first = 0;
4072 } else if (hh != h || ss != s)
4073 bad = 1;
4074 }
4075 }
4076
4077 if (!first && !bad) {
4078 pt_heads = hh;
4079 pt_sectors = ss;
4080 }
4081}
4082
4083void
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004084get_geometry(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004085 int sec_fac;
4086 unsigned long longsectors;
4087
4088 get_sectorsize();
4089 sec_fac = sector_size / 512;
4090#ifdef CONFIG_FEATURE_SUN_LABEL
4091 guess_device_type();
4092#endif
4093 heads = cylinders = sectors = 0;
4094 kern_heads = kern_sectors = 0;
4095 pt_heads = pt_sectors = 0;
4096
4097 get_kernel_geometry();
4098 get_partition_table_geometry();
4099
4100 heads = user_heads ? user_heads :
4101 pt_heads ? pt_heads :
4102 kern_heads ? kern_heads : 255;
4103 sectors = user_sectors ? user_sectors :
4104 pt_sectors ? pt_sectors :
4105 kern_sectors ? kern_sectors : 63;
4106
4107 if (ioctl(fd, BLKGETSIZE, &longsectors))
4108 longsectors = 0;
4109
4110 sector_offset = 1;
4111 if (dos_compatible_flag)
4112 sector_offset = sectors;
4113
4114 cylinders = longsectors / (heads * sectors);
4115 cylinders /= sec_fac;
4116 if (!cylinders)
4117 cylinders = user_cylinders;
4118
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004119 total_number_of_sectors = longsectors;
4120}
4121
4122/*
4123 * Read MBR. Returns:
4124 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4125 * 0: found or created label
4126 * 1: I/O error
4127 */
4128int
4129get_boot(enum action what) {
4130 int i;
4131
4132 partitions = 4;
4133
4134 for (i = 0; i < 4; i++) {
4135 struct pte *pe = &ptes[i];
4136
4137 pe->part_table = pt_offset(MBRbuffer, i);
4138 pe->ext_pointer = NULL;
4139 pe->offset = 0;
4140 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004141#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004142 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004143#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004144 }
4145
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004146#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004147 if (what == create_empty_sun && check_sun_label())
4148 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004149#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004150
4151 memset(MBRbuffer, 0, 512);
4152
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004153#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004154 if (what == create_empty_dos)
4155 goto got_dos_table; /* skip reading disk */
4156
4157 if ((fd = open(disk_device, type_open)) < 0) {
4158 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4159 if (what == try_only)
4160 return 1;
4161 fdisk_fatal(unable_to_open);
4162 } else
4163 printf(_("You will not be able to write "
4164 "the partition table.\n"));
4165 }
4166
4167 if (512 != read(fd, MBRbuffer, 512)) {
4168 if (what == try_only)
4169 return 1;
4170 fdisk_fatal(unable_to_read);
4171 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004172#else
4173 if ((fd = open(disk_device, O_RDONLY)) < 0)
4174 return 1;
4175 if (512 != read(fd, MBRbuffer, 512))
4176 return 1;
4177#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004178
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004179 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004180
4181 update_units();
4182
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004183#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004184 if (check_sun_label())
4185 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004186#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004187
4188#ifdef CONFIG_FEATURE_SGI_LABEL
4189 if (check_sgi_label())
4190 return 0;
4191#endif
4192
4193#ifdef CONFIG_FEATURE_AIX_LABEL
4194 if (check_aix_label())
4195 return 0;
4196#endif
4197
4198#ifdef CONFIG_FEATURE_OSF_LABEL
4199 if (check_osf_label()) {
4200 possibly_osf_label = 1;
4201 if (!valid_part_table_flag(MBRbuffer)) {
4202 osf_label = 1;
4203 return 0;
4204 }
4205 printf(_("This disk has both DOS and BSD magic.\n"
4206 "Give the 'b' command to go to BSD mode.\n"));
4207 }
4208#endif
4209
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004210#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004211got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004212#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004213
4214 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004215#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4216 return -1;
4217#else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004218 switch(what) {
4219 case fdisk:
4220 fprintf(stderr,
4221 _("Device contains neither a valid DOS "
4222 "partition table, nor Sun, SGI or OSF "
4223 "disklabel\n"));
4224#ifdef __sparc__
4225#ifdef CONFIG_FEATURE_SUN_LABEL
4226 create_sunlabel();
4227#endif
4228#else
4229 create_doslabel();
4230#endif
4231 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004232 case try_only:
4233 return -1;
4234 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004235#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004236 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004237#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004238 break;
4239 default:
4240 fprintf(stderr, _("Internal error\n"));
4241 exit(1);
4242 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004243#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004244 }
4245
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004246#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004247 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004248#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004249 warn_geometry();
4250
4251 for (i = 0; i < 4; i++) {
4252 struct pte *pe = &ptes[i];
4253
4254 if (IS_EXTENDED (pe->part_table->sys_ind)) {
4255 if (partitions != 4)
4256 fprintf(stderr, _("Ignoring extra extended "
4257 "partition %d\n"), i + 1);
4258 else
4259 read_extended(i);
4260 }
4261 }
4262
4263 for (i = 3; i < partitions; i++) {
4264 struct pte *pe = &ptes[i];
4265
4266 if (!valid_part_table_flag(pe->sectorbuffer)) {
4267 fprintf(stderr,
4268 _("Warning: invalid flag 0x%04x of partition "
4269 "table %d will be corrected by w(rite)\n"),
4270 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004271#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004272 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004273#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004274 }
4275 }
4276
4277 return 0;
4278}
4279
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004280#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004281/*
4282 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4283 * If the user hits Enter, DFLT is returned.
4284 * Answers like +10 are interpreted as offsets from BASE.
4285 *
4286 * There is no default if DFLT is not between LOW and HIGH.
4287 */
4288static uint
4289read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4290{
4291 uint i;
4292 int default_ok = 1;
4293 static char *ms = NULL;
4294 static int mslen = 0;
4295
4296 if (!ms || strlen(mesg)+100 > mslen) {
4297 mslen = strlen(mesg)+200;
4298 ms = xrealloc(ms,mslen);
4299 }
4300
4301 if (dflt < low || dflt > high)
4302 default_ok = 0;
4303
4304 if (default_ok)
4305 snprintf(ms, mslen, _("%s (%d-%d, default %d): "),
4306 mesg, low, high, dflt);
4307 else
4308 snprintf(ms, mslen, "%s (%d-%d): ",
4309 mesg, low, high);
4310
4311 while (1) {
4312 int use_default = default_ok;
4313
4314 /* ask question and read answer */
4315 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
4316 && *line_ptr != '-' && *line_ptr != '+')
4317 continue;
4318
4319 if (*line_ptr == '+' || *line_ptr == '-') {
4320 i = atoi(line_ptr+1);
4321 if (*line_ptr == '-')
4322 i = -i;
4323 while (isdigit(*++line_ptr))
4324 use_default = 0;
4325 switch (*line_ptr) {
4326 case 'c':
4327 case 'C':
4328 if (!display_in_cyl_units)
4329 i *= heads * sectors;
4330 break;
4331 case 'k':
4332 case 'K':
4333 i *= 2;
4334 i /= (sector_size / 512);
4335 i /= units_per_sector;
4336 break;
4337 case 'm':
4338 case 'M':
4339 i *= 2048;
4340 i /= (sector_size / 512);
4341 i /= units_per_sector;
4342 break;
4343 case 'g':
4344 case 'G':
4345 i *= 2048000;
4346 i /= (sector_size / 512);
4347 i /= units_per_sector;
4348 break;
4349 default:
4350 break;
4351 }
4352 i += base;
4353 } else {
4354 i = atoi(line_ptr);
4355 while (isdigit(*line_ptr)) {
4356 line_ptr++;
4357 use_default = 0;
4358 }
4359 }
4360 if (use_default)
4361 printf(_("Using default value %d\n"), i = dflt);
4362 if (i >= low && i <= high)
4363 break;
4364 else
4365 printf(_("Value out of range.\n"));
4366 }
4367 return i;
4368}
4369
4370int
4371get_partition(int warn, int max) {
4372 struct pte *pe;
4373 int i;
4374
4375 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4376 pe = &ptes[i];
4377
4378 if (warn) {
4379 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4380#ifdef CONFIG_FEATURE_SUN_LABEL
4381 || (sun_label &&
4382 (!sunlabel->partitions[i].num_sectors ||
4383 !sunlabel->infos[i].id))
4384#endif
4385#ifdef CONFIG_FEATURE_SGI_LABEL
4386 || (sgi_label && (!sgi_get_num_sectors(i)))
4387#endif
4388 )
4389 fprintf(stderr,
4390 _("Warning: partition %d has empty type\n"),
4391 i+1);
4392 }
4393 return i;
4394}
4395
4396static int
4397get_existing_partition(int warn, int max) {
4398 int pno = -1;
4399 int i;
4400
4401 for (i = 0; i < max; i++) {
4402 struct pte *pe = &ptes[i];
4403 struct partition *p = pe->part_table;
4404
4405 if (p && !is_cleared_partition(p)) {
4406 if (pno >= 0)
4407 goto not_unique;
4408 pno = i;
4409 }
4410 }
4411 if (pno >= 0) {
4412 printf(_("Selected partition %d\n"), pno+1);
4413 return pno;
4414 }
4415 printf(_("No partition is defined yet!\n"));
4416 return -1;
4417
4418 not_unique:
4419 return get_partition(warn, max);
4420}
4421
4422static int
4423get_nonexisting_partition(int warn, int max) {
4424 int pno = -1;
4425 int i;
4426
4427 for (i = 0; i < max; i++) {
4428 struct pte *pe = &ptes[i];
4429 struct partition *p = pe->part_table;
4430
4431 if (p && is_cleared_partition(p)) {
4432 if (pno >= 0)
4433 goto not_unique;
4434 pno = i;
4435 }
4436 }
4437 if (pno >= 0) {
4438 printf(_("Selected partition %d\n"), pno+1);
4439 return pno;
4440 }
4441 printf(_("All primary partitions have been defined already!\n"));
4442 return -1;
4443
4444 not_unique:
4445 return get_partition(warn, max);
4446}
4447
4448
4449void change_units(void)
4450{
4451 display_in_cyl_units = !display_in_cyl_units;
4452 update_units();
4453 printf(_("Changing display/entry units to %s\n"),
4454 str_units(PLURAL));
4455}
4456
4457static void
4458toggle_active(int i) {
4459 struct pte *pe = &ptes[i];
4460 struct partition *p = pe->part_table;
4461
4462 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
4463 fprintf(stderr,
4464 _("WARNING: Partition %d is an extended partition\n"),
4465 i + 1);
4466 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4467 pe->changed = 1;
4468}
4469
4470static void
4471toggle_dos_compatibility_flag(void) {
4472 dos_compatible_flag = ~dos_compatible_flag;
4473 if (dos_compatible_flag) {
4474 sector_offset = sectors;
4475 printf(_("DOS Compatibility flag is set\n"));
4476 }
4477 else {
4478 sector_offset = 1;
4479 printf(_("DOS Compatibility flag is not set\n"));
4480 }
4481}
4482
4483static void
4484delete_partition(int i) {
4485 struct pte *pe = &ptes[i];
4486 struct partition *p = pe->part_table;
4487 struct partition *q = pe->ext_pointer;
4488
4489/* Note that for the fifth partition (i == 4) we don't actually
4490 * decrement partitions.
4491 */
4492
4493 if (warn_geometry())
4494 return; /* C/H/S not set */
4495 pe->changed = 1;
4496
4497#ifdef CONFIG_FEATURE_SUN_LABEL
4498 if (sun_label) {
4499 sun_delete_partition(i);
4500 return;
4501 }
4502#endif
4503#ifdef CONFIG_FEATURE_SGI_LABEL
4504 if (sgi_label) {
4505 sgi_delete_partition(i);
4506 return;
4507 }
4508#endif
4509
4510 if (i < 4) {
4511 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
4512 partitions = 4;
4513 ptes[ext_index].ext_pointer = NULL;
4514 extended_offset = 0;
4515 }
4516 clear_partition(p);
4517 return;
4518 }
4519
4520 if (!q->sys_ind && i > 4) {
4521 /* the last one in the chain - just delete */
4522 --partitions;
4523 --i;
4524 clear_partition(ptes[i].ext_pointer);
4525 ptes[i].changed = 1;
4526 } else {
4527 /* not the last one - further ones will be moved down */
4528 if (i > 4) {
4529 /* delete this link in the chain */
4530 p = ptes[i-1].ext_pointer;
4531 *p = *q;
4532 set_start_sect(p, get_start_sect(q));
4533 set_nr_sects(p, get_nr_sects(q));
4534 ptes[i-1].changed = 1;
4535 } else if (partitions > 5) { /* 5 will be moved to 4 */
4536 /* the first logical in a longer chain */
4537 pe = &ptes[5];
4538
4539 if (pe->part_table) /* prevent SEGFAULT */
4540 set_start_sect(pe->part_table,
4541 get_partition_start(pe) -
4542 extended_offset);
4543 pe->offset = extended_offset;
4544 pe->changed = 1;
4545 }
4546
4547 if (partitions > 5) {
4548 partitions--;
4549 while (i < partitions) {
4550 ptes[i] = ptes[i+1];
4551 i++;
4552 }
4553 } else
4554 /* the only logical: clear only */
4555 clear_partition(ptes[i].part_table);
4556 }
4557}
4558
4559static void
4560change_sysid(void) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004561 int i, sys, origsys;
4562 struct partition *p;
4563
4564 i = get_existing_partition(0, partitions);
4565 if (i == -1)
4566 return;
4567 p = ptes[i].part_table;
4568 origsys = sys = get_sysid(i);
4569
4570 /* if changing types T to 0 is allowed, then
4571 the reverse change must be allowed, too */
4572 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4573 printf(_("Partition %d does not exist yet!\n"), i + 1);
4574 else while (1) {
4575 sys = read_hex (get_sys_types());
4576
4577 if (!sys && !sgi_label && !sun_label) {
4578 printf(_("Type 0 means free space to many systems\n"
4579 "(but not to Linux). Having partitions of\n"
4580 "type 0 is probably unwise. You can delete\n"
4581 "a partition using the `d' command.\n"));
4582 /* break; */
4583 }
4584
4585 if (!sun_label && !sgi_label) {
4586 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
4587 printf(_("You cannot change a partition into"
4588 " an extended one or vice versa\n"
4589 "Delete it first.\n"));
4590 break;
4591 }
4592 }
4593
4594 if (sys < 256) {
4595#ifdef CONFIG_FEATURE_SUN_LABEL
4596 if (sun_label && i == 2 && sys != WHOLE_DISK)
4597 printf(_("Consider leaving partition 3 "
4598 "as Whole disk (5),\n"
4599 "as SunOS/Solaris expects it and "
4600 "even Linux likes it.\n\n"));
4601#endif
4602#ifdef CONFIG_FEATURE_SGI_LABEL
4603 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4604 || (i == 8 && sys != 0)))
4605 printf(_("Consider leaving partition 9 "
4606 "as volume header (0),\nand "
4607 "partition 11 as entire volume (6)"
4608 "as IRIX expects it.\n\n"));
4609#endif
4610 if (sys == origsys)
4611 break;
4612#ifdef CONFIG_FEATURE_SUN_LABEL
4613 if (sun_label) {
4614 sun_change_sysid(i, sys);
4615 } else
4616#endif
4617#ifdef CONFIG_FEATURE_SGI_LABEL
4618 if (sgi_label) {
4619 sgi_change_sysid(i, sys);
4620 } else
4621#endif
4622 p->sys_ind = sys;
4623 printf (_("Changed system type of partition %d "
4624 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004625 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004626 ptes[i].changed = 1;
4627 if (is_dos_partition(origsys) ||
4628 is_dos_partition(sys))
4629 dos_changed = 1;
4630 break;
4631 }
4632 }
4633}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004634#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4635
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004636
4637/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4638 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4639 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4640 * Lubkin Oct. 1991). */
4641
4642static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
4643 int spc = heads * sectors;
4644
4645 *c = ls / spc;
4646 ls = ls % spc;
4647 *h = ls / sectors;
4648 *s = ls % sectors + 1; /* sectors count from 1 */
4649}
4650
4651static void check_consistency(const struct partition *p, int partition) {
4652 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4653 uint pec, peh, pes; /* physical ending c, h, s */
4654 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4655 uint lec, leh, les; /* logical ending c, h, s */
4656
4657 if (!heads || !sectors || (partition >= 4))
4658 return; /* do not check extended partitions */
4659
4660/* physical beginning c, h, s */
4661 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4662 pbh = p->head;
4663 pbs = p->sector & 0x3f;
4664
4665/* physical ending c, h, s */
4666 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4667 peh = p->end_head;
4668 pes = p->end_sector & 0x3f;
4669
4670/* compute logical beginning (c, h, s) */
4671 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4672
4673/* compute logical ending (c, h, s) */
4674 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4675
4676/* Same physical / logical beginning? */
4677 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4678 printf(_("Partition %d has different physical/logical "
4679 "beginnings (non-Linux?):\n"), partition + 1);
4680 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4681 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4682 }
4683
4684/* Same physical / logical ending? */
4685 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4686 printf(_("Partition %d has different physical/logical "
4687 "endings:\n"), partition + 1);
4688 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4689 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4690 }
4691
4692#if 0
4693/* Beginning on cylinder boundary? */
4694 if (pbh != !pbc || pbs != 1) {
4695 printf(_("Partition %i does not start on cylinder "
4696 "boundary:\n"), partition + 1);
4697 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4698 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4699 }
4700#endif
4701
4702/* Ending on cylinder boundary? */
4703 if (peh != (heads - 1) || pes != sectors) {
4704 printf(_("Partition %i does not end on cylinder boundary:\n"),
4705 partition + 1);
4706#if 0
4707 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4708 printf(_("should be (%d, %d, %d)\n"),
4709 pec, heads - 1, sectors);
4710#endif
4711 }
4712}
4713
4714static void
4715list_disk_geometry(void) {
4716 long long bytes = (long long) total_number_of_sectors * 512;
4717 long megabytes = bytes/1000000;
4718
4719 if (megabytes < 10000)
4720 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
4721 disk_device, megabytes, bytes);
4722 else
4723 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
4724 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
4725 printf(_("%d heads, %d sectors/track, %d cylinders"),
4726 heads, sectors, cylinders);
4727 if (units_per_sector == 1)
4728 printf(_(", total %lu sectors"),
4729 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004730 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004731 str_units(PLURAL),
4732 units_per_sector, sector_size, units_per_sector * sector_size);
4733}
4734
4735/*
4736 * Check whether partition entries are ordered by their starting positions.
4737 * Return 0 if OK. Return i if partition i should have been earlier.
4738 * Two separate checks: primary and logical partitions.
4739 */
4740static int
4741wrong_p_order(int *prev) {
4742 const struct pte *pe;
4743 const struct partition *p;
4744 uint last_p_start_pos = 0, p_start_pos;
4745 int i, last_i = 0;
4746
4747 for (i = 0 ; i < partitions; i++) {
4748 if (i == 4) {
4749 last_i = 4;
4750 last_p_start_pos = 0;
4751 }
4752 pe = &ptes[i];
4753 if ((p = pe->part_table)->sys_ind) {
4754 p_start_pos = get_partition_start(pe);
4755
4756 if (last_p_start_pos > p_start_pos) {
4757 if (prev)
4758 *prev = last_i;
4759 return i;
4760 }
4761
4762 last_p_start_pos = p_start_pos;
4763 last_i = i;
4764 }
4765 }
4766 return 0;
4767}
4768
4769#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4770/*
4771 * Fix the chain of logicals.
4772 * extended_offset is unchanged, the set of sectors used is unchanged
4773 * The chain is sorted so that sectors increase, and so that
4774 * starting sectors increase.
4775 *
4776 * After this it may still be that cfdisk doesnt like the table.
4777 * (This is because cfdisk considers expanded parts, from link to
4778 * end of partition, and these may still overlap.)
4779 * Now
4780 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4781 * may help.
4782 */
4783static void
4784fix_chain_of_logicals(void) {
4785 int j, oj, ojj, sj, sjj;
4786 struct partition *pj,*pjj,tmp;
4787
4788 /* Stage 1: sort sectors but leave sector of part 4 */
4789 /* (Its sector is the global extended_offset.) */
4790 stage1:
4791 for (j = 5; j < partitions-1; j++) {
4792 oj = ptes[j].offset;
4793 ojj = ptes[j+1].offset;
4794 if (oj > ojj) {
4795 ptes[j].offset = ojj;
4796 ptes[j+1].offset = oj;
4797 pj = ptes[j].part_table;
4798 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4799 pjj = ptes[j+1].part_table;
4800 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4801 set_start_sect(ptes[j-1].ext_pointer,
4802 ojj-extended_offset);
4803 set_start_sect(ptes[j].ext_pointer,
4804 oj-extended_offset);
4805 goto stage1;
4806 }
4807 }
4808
4809 /* Stage 2: sort starting sectors */
4810 stage2:
4811 for (j = 4; j < partitions-1; j++) {
4812 pj = ptes[j].part_table;
4813 pjj = ptes[j+1].part_table;
4814 sj = get_start_sect(pj);
4815 sjj = get_start_sect(pjj);
4816 oj = ptes[j].offset;
4817 ojj = ptes[j+1].offset;
4818 if (oj+sj > ojj+sjj) {
4819 tmp = *pj;
4820 *pj = *pjj;
4821 *pjj = tmp;
4822 set_start_sect(pj, ojj+sjj-oj);
4823 set_start_sect(pjj, oj+sj-ojj);
4824 goto stage2;
4825 }
4826 }
4827
4828 /* Probably something was changed */
4829 for (j = 4; j < partitions; j++)
4830 ptes[j].changed = 1;
4831}
4832
4833
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004834static void
4835fix_partition_table_order(void) {
4836 struct pte *pei, *pek;
4837 int i,k;
4838
4839 if (!wrong_p_order(NULL)) {
4840 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4841 return;
4842 }
4843
4844 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4845 /* partition i should have come earlier, move it */
4846 /* We have to move data in the MBR */
4847 struct partition *pi, *pk, *pe, pbuf;
4848 pei = &ptes[i];
4849 pek = &ptes[k];
4850
4851 pe = pei->ext_pointer;
4852 pei->ext_pointer = pek->ext_pointer;
4853 pek->ext_pointer = pe;
4854
4855 pi = pei->part_table;
4856 pk = pek->part_table;
4857
4858 memmove(&pbuf, pi, sizeof(struct partition));
4859 memmove(pi, pk, sizeof(struct partition));
4860 memmove(pk, &pbuf, sizeof(struct partition));
4861
4862 pei->changed = pek->changed = 1;
4863 }
4864
4865 if (i)
4866 fix_chain_of_logicals();
4867
4868 printf("Done.\n");
4869
4870}
4871#endif
4872
4873static void
4874list_table(int xtra) {
4875 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004876 int i, w;
4877
4878#ifdef CONFIG_FEATURE_SUN_LABEL
4879 if (sun_label) {
4880 sun_list_table(xtra);
4881 return;
4882 }
4883#endif
4884
4885#ifdef CONFIG_FEATURE_SGI_LABEL
4886 if (sgi_label) {
4887 sgi_list_table(xtra);
4888 return;
4889 }
4890#endif
4891
4892 list_disk_geometry();
4893
4894#ifdef CONFIG_FEATURE_OSF_LABEL
4895 if (osf_label) {
4896 xbsd_print_disklabel(xtra);
4897 return;
4898 }
4899#endif
4900
4901 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4902 but if the device name ends in a digit, say /dev/foo1,
4903 then the partition is called /dev/foo1p3. */
4904 w = strlen(disk_device);
4905 if (w && isdigit(disk_device[w-1]))
4906 w++;
4907 if (w < 5)
4908 w = 5;
4909
4910 printf(_("%*s Boot Start End Blocks Id System\n"),
4911 w+1, _("Device"));
4912
4913 for (i = 0; i < partitions; i++) {
4914 const struct pte *pe = &ptes[i];
4915
4916 p = pe->part_table;
4917 if (p && !is_cleared_partition(p)) {
4918 unsigned int psects = get_nr_sects(p);
4919 unsigned int pblocks = psects;
4920 unsigned int podd = 0;
4921
4922 if (sector_size < 1024) {
4923 pblocks /= (1024 / sector_size);
4924 podd = psects % (1024 / sector_size);
4925 }
4926 if (sector_size > 1024)
4927 pblocks *= (sector_size / 1024);
4928 printf(
4929 "%s %c %9ld %9ld %9ld%c %2x %s\n",
4930 partname(disk_device, i+1, w+2),
4931/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4932 ? '*' : '?',
4933/* start */ (long) cround(get_partition_start(pe)),
4934/* end */ (long) cround(get_partition_start(pe) + psects
4935 - (psects ? 1 : 0)),
4936/* odd flag on end */ (long) pblocks, podd ? '+' : ' ',
4937/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004938/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004939 check_consistency(p, i);
4940 }
4941 }
4942
4943 /* Is partition table in disk order? It need not be, but... */
4944 /* partition table entries are not checked for correct order if this
4945 is a sgi, sun or aix labeled disk... */
4946 if (dos_label && wrong_p_order(NULL)) {
4947 printf(_("\nPartition table entries are not in disk order\n"));
4948 }
4949}
4950
4951#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4952static void
4953x_list_table(int extend) {
4954 const struct pte *pe;
4955 const struct partition *p;
4956 int i;
4957
4958 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4959 disk_device, heads, sectors, cylinders);
4960 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4961 for (i = 0 ; i < partitions; i++) {
4962 pe = &ptes[i];
4963 p = (extend ? pe->ext_pointer : pe->part_table);
4964 if (p != NULL) {
4965 printf("%2d %02x%4d%4d%5d%4d%4d%5d%9d%9d %02x\n",
4966 i + 1, p->boot_ind, p->head,
4967 sector(p->sector),
4968 cylinder(p->sector, p->cyl), p->end_head,
4969 sector(p->end_sector),
4970 cylinder(p->end_sector, p->end_cyl),
4971 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4972 if (p->sys_ind)
4973 check_consistency(p, i);
4974 }
4975 }
4976}
4977#endif
4978
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004979#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004980static void
4981fill_bounds(uint *first, uint *last) {
4982 int i;
4983 const struct pte *pe = &ptes[0];
4984 const struct partition *p;
4985
4986 for (i = 0; i < partitions; pe++,i++) {
4987 p = pe->part_table;
4988 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
4989 first[i] = 0xffffffff;
4990 last[i] = 0;
4991 } else {
4992 first[i] = get_partition_start(pe);
4993 last[i] = first[i] + get_nr_sects(p) - 1;
4994 }
4995 }
4996}
4997
4998static void
4999check(int n, uint h, uint s, uint c, uint start) {
5000 uint total, real_s, real_c;
5001
5002 real_s = sector(s) - 1;
5003 real_c = cylinder(s, c);
5004 total = (real_c * sectors + real_s) * heads + h;
5005 if (!total)
5006 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
5007 if (h >= heads)
5008 fprintf(stderr,
5009 _("Partition %d: head %d greater than maximum %d\n"),
5010 n, h + 1, heads);
5011 if (real_s >= sectors)
5012 fprintf(stderr, _("Partition %d: sector %d greater than "
5013 "maximum %d\n"), n, s, sectors);
5014 if (real_c >= cylinders)
5015 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
5016 "maximum %d\n"), n, real_c + 1, cylinders);
5017 if (cylinders <= 1024 && start != total)
5018 fprintf(stderr,
5019 _("Partition %d: previous sectors %d disagrees with "
5020 "total %d\n"), n, start, total);
5021}
5022
5023static void
5024verify(void) {
5025 int i, j;
5026 uint total = 1;
5027 uint first[partitions], last[partitions];
5028 struct partition *p;
5029
5030 if (warn_geometry())
5031 return;
5032
5033#ifdef CONFIG_FEATURE_SUN_LABEL
5034 if (sun_label) {
5035 verify_sun();
5036 return;
5037 }
5038#endif
5039#ifdef CONFIG_FEATURE_SGI_LABEL
5040 if (sgi_label) {
5041 verify_sgi(1);
5042 return;
5043 }
5044#endif
5045
5046 fill_bounds(first, last);
5047 for (i = 0; i < partitions; i++) {
5048 struct pte *pe = &ptes[i];
5049
5050 p = pe->part_table;
5051 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
5052 check_consistency(p, i);
5053 if (get_partition_start(pe) < first[i])
5054 printf(_("Warning: bad start-of-data in "
5055 "partition %d\n"), i + 1);
5056 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5057 last[i]);
5058 total += last[i] + 1 - first[i];
5059 for (j = 0; j < i; j++)
5060 if ((first[i] >= first[j] && first[i] <= last[j])
5061 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5062 printf(_("Warning: partition %d overlaps "
5063 "partition %d.\n"), j + 1, i + 1);
5064 total += first[i] >= first[j] ?
5065 first[i] : first[j];
5066 total -= last[i] <= last[j] ?
5067 last[i] : last[j];
5068 }
5069 }
5070 }
5071
5072 if (extended_offset) {
5073 struct pte *pex = &ptes[ext_index];
5074 uint e_last = get_start_sect(pex->part_table) +
5075 get_nr_sects(pex->part_table) - 1;
5076
5077 for (i = 4; i < partitions; i++) {
5078 total++;
5079 p = ptes[i].part_table;
5080 if (!p->sys_ind) {
5081 if (i != 4 || i + 1 < partitions)
5082 printf(_("Warning: partition %d "
5083 "is empty\n"), i + 1);
5084 }
5085 else if (first[i] < extended_offset ||
5086 last[i] > e_last)
5087 printf(_("Logical partition %d not entirely in "
5088 "partition %d\n"), i + 1, ext_index + 1);
5089 }
5090 }
5091
5092 if (total > heads * sectors * cylinders)
5093 printf(_("Total allocated sectors %d greater than the maximum "
5094 "%d\n"), total, heads * sectors * cylinders);
5095 else if ((total = heads * sectors * cylinders - total) != 0)
5096 printf(_("%d unallocated sectors\n"), total);
5097}
5098
5099static void
5100add_partition(int n, int sys) {
5101 char mesg[256]; /* 48 does not suffice in Japanese */
5102 int i, readed = 0;
5103 struct partition *p = ptes[n].part_table;
5104 struct partition *q = ptes[ext_index].part_table;
5105 uint start, stop = 0, limit, temp,
5106 first[partitions], last[partitions];
5107
5108 if (p && p->sys_ind) {
5109 printf(_("Partition %d is already defined. Delete "
5110 "it before re-adding it.\n"), n + 1);
5111 return;
5112 }
5113 fill_bounds(first, last);
5114 if (n < 4) {
5115 start = sector_offset;
5116 if (display_in_cyl_units)
5117 limit = heads * sectors * cylinders - 1;
5118 else
5119 limit = total_number_of_sectors - 1;
5120 if (extended_offset) {
5121 first[ext_index] = extended_offset;
5122 last[ext_index] = get_start_sect(q) +
5123 get_nr_sects(q) - 1;
5124 }
5125 } else {
5126 start = extended_offset + sector_offset;
5127 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5128 }
5129 if (display_in_cyl_units)
5130 for (i = 0; i < partitions; i++)
5131 first[i] = (cround(first[i]) - 1) * units_per_sector;
5132
5133 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5134 do {
5135 temp = start;
5136 for (i = 0; i < partitions; i++) {
5137 int lastplusoff;
5138
5139 if (start == ptes[i].offset)
5140 start += sector_offset;
5141 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
5142 if (start >= first[i] && start <= lastplusoff)
5143 start = lastplusoff + 1;
5144 }
5145 if (start > limit)
5146 break;
5147 if (start >= temp+units_per_sector && readed) {
5148 printf(_("Sector %d is already allocated\n"), temp);
5149 temp = start;
5150 readed = 0;
5151 }
5152 if (!readed && start == temp) {
5153 uint saved_start;
5154
5155 saved_start = start;
5156 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5157 0, mesg);
5158 if (display_in_cyl_units) {
5159 start = (start - 1) * units_per_sector;
5160 if (start < saved_start) start = saved_start;
5161 }
5162 readed = 1;
5163 }
5164 } while (start != temp || !readed);
5165 if (n > 4) { /* NOT for fifth partition */
5166 struct pte *pe = &ptes[n];
5167
5168 pe->offset = start - sector_offset;
5169 if (pe->offset == extended_offset) { /* must be corrected */
5170 pe->offset++;
5171 if (sector_offset == 1)
5172 start++;
5173 }
5174 }
5175
5176 for (i = 0; i < partitions; i++) {
5177 struct pte *pe = &ptes[i];
5178
5179 if (start < pe->offset && limit >= pe->offset)
5180 limit = pe->offset - 1;
5181 if (start < first[i] && limit >= first[i])
5182 limit = first[i] - 1;
5183 }
5184 if (start > limit) {
5185 printf(_("No free sectors available\n"));
5186 if (n > 4)
5187 partitions--;
5188 return;
5189 }
5190 if (cround(start) == cround(limit)) {
5191 stop = limit;
5192 } else {
5193 snprintf(mesg, sizeof(mesg),
5194 _("Last %s or +size or +sizeM or +sizeK"),
5195 str_units(SINGULAR));
5196 stop = read_int(cround(start), cround(limit), cround(limit),
5197 cround(start), mesg);
5198 if (display_in_cyl_units) {
5199 stop = stop * units_per_sector - 1;
5200 if (stop >limit)
5201 stop = limit;
5202 }
5203 }
5204
5205 set_partition(n, 0, start, stop, sys);
5206 if (n > 4)
5207 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5208
5209 if (IS_EXTENDED (sys)) {
5210 struct pte *pe4 = &ptes[4];
5211 struct pte *pen = &ptes[n];
5212
5213 ext_index = n;
5214 pen->ext_pointer = p;
5215 pe4->offset = extended_offset = start;
5216 pe4->sectorbuffer = xcalloc(1, sector_size);
5217 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5218 pe4->ext_pointer = pe4->part_table + 1;
5219 pe4->changed = 1;
5220 partitions = 5;
5221 }
5222}
5223
5224static void
5225add_logical(void) {
5226 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5227 struct pte *pe = &ptes[partitions];
5228
5229 pe->sectorbuffer = xcalloc(1, sector_size);
5230 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5231 pe->ext_pointer = pe->part_table + 1;
5232 pe->offset = 0;
5233 pe->changed = 1;
5234 partitions++;
5235 }
5236 add_partition(partitions - 1, LINUX_NATIVE);
5237}
5238
5239static void
5240new_partition(void) {
5241 int i, free_primary = 0;
5242
5243 if (warn_geometry())
5244 return;
5245
5246#ifdef CONFIG_FEATURE_SUN_LABEL
5247 if (sun_label) {
5248 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5249 return;
5250 }
5251#endif
5252#ifdef CONFIG_FEATURE_SGI_LABEL
5253 if (sgi_label) {
5254 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5255 return;
5256 }
5257#endif
5258#ifdef CONFIG_FEATURE_AIX_LABEL
5259 if (aix_label) {
5260 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5261 "\n\tIf you want to add DOS-type partitions, create"
5262 "\n\ta new empty DOS partition table first. (Use o.)"
5263 "\n\tWARNING: "
5264 "This will destroy the present disk contents.\n"));
5265 return;
5266 }
5267#endif
5268
5269 if (partitions >= MAXIMUM_PARTS) {
5270 printf(_("The maximum number of partitions has been created\n"));
5271 return;
5272 }
5273
5274 for (i = 0; i < 4; i++)
5275 free_primary += !ptes[i].part_table->sys_ind;
5276 if (!free_primary) {
5277 if (extended_offset)
5278 add_logical();
5279 else
5280 printf(_("You must delete some partition and add "
5281 "an extended partition first\n"));
5282 } else {
5283 char c, line[LINE_LENGTH];
5284 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5285 "partition (1-4)\n",
5286 "Command action", (extended_offset ?
5287 "l logical (5 or over)" : "e extended"));
5288 while (1) {
5289 if ((c = read_char(line)) == 'p' || c == 'P') {
5290 i = get_nonexisting_partition(0, 4);
5291 if (i >= 0)
5292 add_partition(i, LINUX_NATIVE);
5293 return;
5294 }
5295 else if (c == 'l' && extended_offset) {
5296 add_logical();
5297 return;
5298 }
5299 else if (c == 'e' && !extended_offset) {
5300 i = get_nonexisting_partition(0, 4);
5301 if (i >= 0)
5302 add_partition(i, EXTENDED);
5303 return;
5304 }
5305 else
5306 printf(_("Invalid partition number "
5307 "for type `%c'\n"), c);
5308 }
5309 }
5310}
5311
5312static void
5313write_table(void) {
5314 int i;
5315
5316 if (dos_label) {
5317 for (i=0; i<3; i++)
5318 if (ptes[i].changed)
5319 ptes[3].changed = 1;
5320 for (i = 3; i < partitions; i++) {
5321 struct pte *pe = &ptes[i];
5322
5323 if (pe->changed) {
5324 write_part_table_flag(pe->sectorbuffer);
5325 write_sector(pe->offset, pe->sectorbuffer);
5326 }
5327 }
5328 }
5329#ifdef CONFIG_FEATURE_SGI_LABEL
5330 else if (sgi_label) {
5331 /* no test on change? the printf below might be mistaken */
5332 sgi_write_table();
5333 }
5334#endif
5335#ifdef CONFIG_FEATURE_SUN_LABEL
5336 else if (sun_label) {
5337 int needw = 0;
5338
5339 for (i=0; i<8; i++)
5340 if (ptes[i].changed)
5341 needw = 1;
5342 if (needw)
5343 sun_write_table();
5344 }
5345#endif
5346
5347 printf(_("The partition table has been altered!\n\n"));
5348 reread_partition_table(1);
5349}
5350
5351void
5352reread_partition_table(int leave) {
5353 int error = 0;
5354 int i;
5355
5356 printf(_("Calling ioctl() to re-read partition table.\n"));
5357 sync();
5358 sleep(2);
5359 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5360 error = errno;
5361 } else {
5362 /* some kernel versions (1.2.x) seem to have trouble
5363 rereading the partition table, but if asked to do it
5364 twice, the second time works. - biro@yggdrasil.com */
5365 sync();
5366 sleep(2);
5367 if ((i = ioctl(fd, BLKRRPART)) != 0)
5368 error = errno;
5369 }
5370
5371 if (i) {
5372 printf(_("\nWARNING: Re-reading the partition table "
5373 "failed with error %d: %s.\n"
5374 "The kernel still uses the old table.\n"
5375 "The new table will be used "
5376 "at the next reboot.\n"),
5377 error, strerror(error));
5378 }
5379
5380 if (dos_changed)
5381 printf(
5382 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5383 "partitions, please see the fdisk manual page for additional\n"
5384 "information.\n"));
5385
5386 if (leave) {
5387 close(fd);
5388
5389 printf(_("Syncing disks.\n"));
5390 sync();
5391 sleep(4); /* for sync() */
5392 exit(!!i);
5393 }
5394}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005395#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005396
5397#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5398#define MAX_PER_LINE 16
5399static void
5400print_buffer(char pbuffer[]) {
5401 int i,
5402 l;
5403
5404 for (i = 0, l = 0; i < sector_size; i++, l++) {
5405 if (l == 0)
5406 printf("0x%03X:", i);
5407 printf(" %02X", (unsigned char) pbuffer[i]);
5408 if (l == MAX_PER_LINE - 1) {
5409 printf("\n");
5410 l = -1;
5411 }
5412 }
5413 if (l > 0)
5414 printf("\n");
5415 printf("\n");
5416}
5417
5418
5419static void
5420print_raw(void) {
5421 int i;
5422
5423 printf(_("Device: %s\n"), disk_device);
5424#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5425 if (sun_label || sgi_label)
5426 print_buffer(MBRbuffer);
5427 else
5428#endif
5429 for (i = 3; i < partitions; i++)
5430 print_buffer(ptes[i].sectorbuffer);
5431}
5432
5433static void
5434move_begin(int i) {
5435 struct pte *pe = &ptes[i];
5436 struct partition *p = pe->part_table;
5437 uint new, first;
5438
5439 if (warn_geometry())
5440 return;
5441 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
5442 printf(_("Partition %d has no data area\n"), i + 1);
5443 return;
5444 }
5445 first = get_partition_start(pe);
5446 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
5447 _("New beginning of data")) - pe->offset;
5448
5449 if (new != get_nr_sects(p)) {
5450 first = get_nr_sects(p) + get_start_sect(p) - new;
5451 set_nr_sects(p, first);
5452 set_start_sect(p, new);
5453 pe->changed = 1;
5454 }
5455}
5456
5457static void
5458xselect(void) {
5459 char c;
5460
5461 while(1) {
5462 putchar('\n');
5463 c = tolower(read_char(_("Expert command (m for help): ")));
5464 switch (c) {
5465 case 'a':
5466#ifdef CONFIG_FEATURE_SUN_LABEL
5467 if (sun_label)
5468 sun_set_alt_cyl();
5469#endif
5470 break;
5471 case 'b':
5472 if (dos_label)
5473 move_begin(get_partition(0, partitions));
5474 break;
5475 case 'c':
5476 user_cylinders = cylinders =
5477 read_int(1, cylinders, 1048576, 0,
5478 _("Number of cylinders"));
5479#ifdef CONFIG_FEATURE_SUN_LABEL
5480 if (sun_label)
5481 sun_set_ncyl(cylinders);
5482#endif
5483 if (dos_label)
5484 warn_cylinders();
5485 break;
5486 case 'd':
5487 print_raw();
5488 break;
5489 case 'e':
5490#ifdef CONFIG_FEATURE_SGI_LABEL
5491 if (sgi_label)
5492 sgi_set_xcyl();
5493 else
5494#endif
5495#ifdef CONFIG_FEATURE_SUN_LABEL
5496 if (sun_label)
5497 sun_set_xcyl();
5498 else
5499#endif
5500 if (dos_label)
5501 x_list_table(1);
5502 break;
5503 case 'f':
5504 if (dos_label)
5505 fix_partition_table_order();
5506 break;
5507 case 'g':
5508#ifdef CONFIG_FEATURE_SGI_LABEL
5509 create_sgilabel();
5510#endif
5511 break;
5512 case 'h':
5513 user_heads = heads = read_int(1, heads, 256, 0,
5514 _("Number of heads"));
5515 update_units();
5516 break;
5517 case 'i':
5518#ifdef CONFIG_FEATURE_SUN_LABEL
5519 if (sun_label)
5520 sun_set_ilfact();
5521#endif
5522 break;
5523 case 'o':
5524#ifdef CONFIG_FEATURE_SUN_LABEL
5525 if (sun_label)
5526 sun_set_rspeed();
5527#endif
5528 break;
5529 case 'p':
5530#ifdef CONFIG_FEATURE_SUN_LABEL
5531 if (sun_label)
5532 list_table(1);
5533 else
5534#endif
5535 x_list_table(0);
5536 break;
5537 case 'q':
5538 close(fd);
5539 printf("\n");
5540 exit(0);
5541 case 'r':
5542 return;
5543 case 's':
5544 user_sectors = sectors = read_int(1, sectors, 63, 0,
5545 _("Number of sectors"));
5546 if (dos_compatible_flag) {
5547 sector_offset = sectors;
5548 fprintf(stderr, _("Warning: setting "
5549 "sector offset for DOS "
5550 "compatiblity\n"));
5551 }
5552 update_units();
5553 break;
5554 case 'v':
5555 verify();
5556 break;
5557 case 'w':
5558 write_table(); /* does not return */
5559 break;
5560 case 'y':
5561#ifdef CONFIG_FEATURE_SUN_LABEL
5562 if (sun_label)
5563 sun_set_pcylcount();
5564#endif
5565 break;
5566 default:
5567 xmenu();
5568 }
5569 }
5570}
5571#endif /* ADVANCED mode */
5572
5573static int
5574is_ide_cdrom_or_tape(const char *device) {
5575 FILE *procf;
5576 char buf[100];
5577 struct stat statbuf;
5578 int is_ide = 0;
5579
5580 /* No device was given explicitly, and we are trying some
5581 likely things. But opening /dev/hdc may produce errors like
5582 "hdc: tray open or drive not ready"
5583 if it happens to be a CD-ROM drive. It even happens that
5584 the process hangs on the attempt to read a music CD.
5585 So try to be careful. This only works since 2.1.73. */
5586
5587 if (strncmp("/dev/hd", device, 7))
5588 return 0;
5589
5590 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5591 procf = fopen(buf, "r");
5592 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5593 is_ide = (!strncmp(buf, "cdrom", 5) ||
5594 !strncmp(buf, "tape", 4));
5595 else
5596 /* Now when this proc file does not exist, skip the
5597 device when it is read-only. */
5598 if (stat(device, &statbuf) == 0)
5599 is_ide = ((statbuf.st_mode & 0222) == 0);
5600
5601 if (procf)
5602 fclose(procf);
5603 return is_ide;
5604}
5605
5606static void
5607try(const char *device, int user_specified) {
5608 int gb;
5609
5610 disk_device = device;
5611 if (setjmp(listingbuf))
5612 return;
5613 if (!user_specified)
5614 if (is_ide_cdrom_or_tape(device))
5615 return;
5616 if ((fd = open(disk_device, type_open)) >= 0) {
5617 gb = get_boot(try_only);
5618 if (gb > 0) { /* I/O error */
5619 close(fd);
5620 } else if (gb < 0) { /* no DOS signature */
5621 list_disk_geometry();
5622 if (aix_label)
5623 return;
5624#ifdef CONFIG_FEATURE_OSF_LABEL
5625 if (btrydev(device) < 0)
5626#endif
5627 fprintf(stderr,
5628 _("Disk %s doesn't contain a valid "
5629 "partition table\n"), device);
5630 close(fd);
5631 } else {
5632 close(fd);
5633 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005634#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005635 if (!sun_label && partitions > 4)
5636 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005637#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005638 }
5639 } else {
5640 /* Ignore other errors, since we try IDE
5641 and SCSI hard disks which may not be
5642 installed on the system. */
5643 if (errno == EACCES) {
5644 fprintf(stderr, _("Cannot open %s\n"), device);
5645 return;
5646 }
5647 }
5648}
5649
5650/* for fdisk -l: try all things in /proc/partitions
5651 that look like a partition name (do not end in a digit) */
5652static void
5653tryprocpt(void) {
5654 FILE *procpt;
5655 char line[100], ptname[100], devname[120], *s;
5656 int ma, mi, sz;
5657
Manuel Novoa III cad53642003-03-19 09:13:01 +00005658 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005659
5660 while (fgets(line, sizeof(line), procpt)) {
5661 if (sscanf (line, " %d %d %d %[^\n ]",
5662 &ma, &mi, &sz, ptname) != 4)
5663 continue;
5664 for (s = ptname; *s; s++);
5665 if (isdigit(s[-1]))
5666 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005667 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005668 try(devname, 0);
5669 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005670#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005671 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005672#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005673}
5674
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005675#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005676static void
5677unknown_command(int c) {
5678 printf(_("%c: unknown command\n"), c);
5679}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005680#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005681
5682int fdisk_main(int argc, char **argv) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005683 int c;
5684#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5685 int optl = 0;
5686#endif
5687#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5688 int opts = 0;
5689#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005690 /*
5691 * Calls:
5692 * fdisk -v
5693 * fdisk -l [-b sectorsize] [-u] device ...
5694 * fdisk -s [partition] ...
5695 * fdisk [-b sectorsize] [-u] device
5696 *
5697 * Options -C, -H, -S set the geometry.
5698 *
5699 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005700 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5701#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5702 "s"
5703#endif
5704 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005705 switch (c) {
5706 case 'b':
5707 /* Ugly: this sector size is really per device,
5708 so cannot be combined with multiple disks,
5709 and te same goes for the C/H/S options.
5710 */
5711 sector_size = atoi(optarg);
5712 if (sector_size != 512 && sector_size != 1024 &&
5713 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005714 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005715 sector_offset = 2;
5716 user_set_sector_size = 1;
5717 break;
5718 case 'C':
5719 user_cylinders = atoi(optarg);
5720 break;
5721 case 'H':
5722 user_heads = atoi(optarg);
5723 if (user_heads <= 0 || user_heads >= 256)
5724 user_heads = 0;
5725 break;
5726 case 'S':
5727 user_sectors = atoi(optarg);
5728 if (user_sectors <= 0 || user_sectors >= 64)
5729 user_sectors = 0;
5730 break;
5731 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005732#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005733 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005734#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005735 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005736#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005737 case 's':
5738 opts = 1;
5739 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005740#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005741 case 'u':
5742 display_in_cyl_units = 0;
5743 break;
5744 case 'V':
5745 case 'v':
5746 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5747 return 0;
5748 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005749 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005750 }
5751 }
5752
5753#if 0
5754 printf(_("This kernel finds the sector size itself - "
5755 "-b option ignored\n"));
5756#else
5757 if (user_set_sector_size && argc-optind != 1)
5758 printf(_("Warning: the -b (set sector size) option should"
5759 " be used with one specified device\n"));
5760#endif
5761
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005762#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005763 if (optl) {
5764 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005765#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005766 type_open = O_RDONLY;
5767 if (argc > optind) {
5768 int k;
5769#if __GNUC__
5770 /* avoid gcc warning:
5771 variable `k' might be clobbered by `longjmp' */
5772 (void)&k;
5773#endif
5774 listing = 1;
5775 for (k=optind; k<argc; k++)
5776 try(argv[k], 1);
5777 } else {
5778 /* we no longer have default device names */
5779 /* but, we can use /proc/partitions instead */
5780 tryprocpt();
5781 }
5782 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005783#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005784 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005785#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005786
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005787#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005788 if (opts) {
5789 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005790 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005791
5792 nowarn = 1;
5793 type_open = O_RDONLY;
5794
5795 opts = argc - optind;
5796 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005797 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005798
5799 for (j = optind; j < argc; j++) {
5800 disk_device = argv[j];
5801 if ((fd = open(disk_device, type_open)) < 0)
5802 fdisk_fatal(unable_to_open);
5803 if (ioctl(fd, BLKGETSIZE, &size))
5804 fdisk_fatal(ioctl_error);
5805 close(fd);
5806 if (opts == 1)
5807 printf("%ld\n", size/2);
5808 else
5809 printf("%s: %ld\n", argv[j], size/2);
5810 }
5811 return 0;
5812 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005813#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005814
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005815#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005816 if (argc-optind == 1)
5817 disk_device = argv[optind];
5818 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005819 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005820
5821 get_boot(fdisk);
5822
5823#ifdef CONFIG_FEATURE_OSF_LABEL
5824 if (osf_label) {
5825 /* OSF label, and no DOS label */
5826 printf(_("Detected an OSF/1 disklabel on %s, entering "
5827 "disklabel mode.\n"),
5828 disk_device);
5829 bselect();
5830 osf_label = 0;
5831 /* If we return we may want to make an empty DOS label? */
5832 }
5833#endif
5834
5835 while (1) {
5836 putchar('\n');
5837 c = tolower(read_char(_("Command (m for help): ")));
5838 switch (c) {
5839 case 'a':
5840 if (dos_label)
5841 toggle_active(get_partition(1, partitions));
5842#ifdef CONFIG_FEATURE_SUN_LABEL
5843 else if (sun_label)
5844 toggle_sunflags(get_partition(1, partitions),
5845 0x01);
5846#endif
5847#ifdef CONFIG_FEATURE_SGI_LABEL
5848 else if (sgi_label)
5849 sgi_set_bootpartition(
5850 get_partition(1, partitions));
5851#endif
5852 else
5853 unknown_command(c);
5854 break;
5855 case 'b':
5856#ifdef CONFIG_FEATURE_SGI_LABEL
5857 if (sgi_label) {
5858 printf(_("\nThe current boot file is: %s\n"),
5859 sgi_get_bootfile());
5860 if (read_chars(_("Please enter the name of the "
5861 "new boot file: ")) == '\n')
5862 printf(_("Boot file unchanged\n"));
5863 else
5864 sgi_set_bootfile(line_ptr);
5865 } else
5866#endif
5867#ifdef CONFIG_FEATURE_OSF_LABEL
5868 bselect();
5869#endif
5870 break;
5871 case 'c':
5872 if (dos_label)
5873 toggle_dos_compatibility_flag();
5874#ifdef CONFIG_FEATURE_SUN_LABEL
5875 else if (sun_label)
5876 toggle_sunflags(get_partition(1, partitions),
5877 0x10);
5878#endif
5879#ifdef CONFIG_FEATURE_SGI_LABEL
5880 else if (sgi_label)
5881 sgi_set_swappartition(
5882 get_partition(1, partitions));
5883#endif
5884 else
5885 unknown_command(c);
5886 break;
5887 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005888 {
5889 int j = get_existing_partition(1, partitions);
5890 if (j >= 0)
5891 delete_partition(j);
5892 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005893 break;
5894 case 'i':
5895#ifdef CONFIG_FEATURE_SGI_LABEL
5896 if (sgi_label)
5897 create_sgiinfo();
5898 else
5899#endif
5900 unknown_command(c);
5901 case 'l':
5902 list_types(get_sys_types());
5903 break;
5904 case 'm':
5905 menu();
5906 break;
5907 case 'n':
5908 new_partition();
5909 break;
5910 case 'o':
5911 create_doslabel();
5912 break;
5913 case 'p':
5914 list_table(0);
5915 break;
5916 case 'q':
5917 close(fd);
5918 printf("\n");
5919 return 0;
5920 case 's':
5921#ifdef CONFIG_FEATURE_SUN_LABEL
5922 create_sunlabel();
5923#endif
5924 break;
5925 case 't':
5926 change_sysid();
5927 break;
5928 case 'u':
5929 change_units();
5930 break;
5931 case 'v':
5932 verify();
5933 break;
5934 case 'w':
5935 write_table(); /* does not return */
5936 break;
5937#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5938 case 'x':
5939#ifdef CONFIG_FEATURE_SGI_LABEL
5940 if (sgi_label) {
5941 fprintf(stderr,
5942 _("\n\tSorry, no experts menu for SGI "
5943 "partition tables available.\n\n"));
5944 } else
5945#endif
5946
5947 xselect();
5948 break;
5949#endif
5950 default:
5951 unknown_command(c);
5952 menu();
5953 }
5954 }
5955 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005956#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005957}