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