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