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