blob: 33ad84702852997e726d2e50988197e2b6e5e5a2 [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)
Rob Landleyb73451d2006-02-24 16:29:00 +00004 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (Busybox port)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005 *
Rob Landleyb73451d2006-02-24 16:29:00 +00006 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00007 */
8
Eric Andersen99a75d12003-08-08 20:04:56 +00009#define UTIL_LINUX_VERSION "2.12"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000010
11#define PROC_PARTITIONS "/proc/partitions"
12
Eric Andersen256c4fd2004-05-19 09:00:00 +000013#include <features.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014#include <sys/types.h>
15#include <sys/stat.h> /* stat */
16#include <ctype.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <errno.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <setjmp.h>
24#include <assert.h> /* assert */
25#include <getopt.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000026#include <endian.h>
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000027#include <sys/ioctl.h>
28#include <sys/param.h>
Eric Andersen040f4402003-07-30 08:40:37 +000029#include <sys/sysmacros.h> /* major */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030
Eric Andersenacd244a2002-12-11 03:49:33 +000031#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
32
33/* Copied from linux/major.h */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +000034#define FLOPPY_MAJOR 2
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000035
36#include <sys/utsname.h>
37
38#include "busybox.h"
39
40#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
41
42#define DKTYPENAMES
43
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000044#define BLKRRPART _IO(0x12,95) /* re-read partition table */
45#define BLKGETSIZE _IO(0x12,96) /* return device size */
46#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
47#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
Eric Andersenf6067be2003-11-03 08:59:51 +000048
49/* Avoid conflicts with the 2.6 kernel headers, which define
Eric Andersenc7bda1c2004-03-15 08:29:22 +000050 * _IOR rather differently */
Eric Andersenf6067be2003-11-03 08:59:51 +000051#undef _IOR
52#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
Eric Andersend4f7a5e2003-12-12 19:05:15 +000053#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000054
55/*
56 fdisk.h
57*/
58
59#define DEFAULT_SECTOR_SIZE 512
60#define MAX_SECTOR_SIZE 2048
61#define SECTOR_SIZE 512 /* still used in BSD code */
62#define MAXIMUM_PARTS 60
63
64#define ACTIVE_FLAG 0x80
65
66#define EXTENDED 0x05
67#define WIN98_EXTENDED 0x0f
68#define LINUX_PARTITION 0x81
69#define LINUX_SWAP 0x82
70#define LINUX_NATIVE 0x83
71#define LINUX_EXTENDED 0x85
72#define LINUX_LVM 0x8e
73#define LINUX_RAID 0xfd
74
75#define SUNOS_SWAP 3
76#define WHOLE_DISK 5
77
78#define IS_EXTENDED(i) \
79 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
80
81#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
82
83#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
84#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
85
Eric Andersen7495b0d2004-02-06 05:26:58 +000086#ifdef CONFIG_FEATURE_SUN_LABEL
87#define SCSI_IOCTL_GET_IDLUN 0x5382
88#endif
89
Eric Andersend3652bf2003-08-06 09:07:37 +000090
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000091/* including <linux/hdreg.h> also fails */
92struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000093 unsigned char heads;
94 unsigned char sectors;
95 unsigned short cylinders;
96 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000097};
98
99#define HDIO_GETGEO 0x0301 /* get device geometry */
100
101
102struct systypes {
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000103 const char *name;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000104};
105
Rob Landleyb73451d2006-02-24 16:29:00 +0000106static uint sector_size = DEFAULT_SECTOR_SIZE;
107static uint user_set_sector_size;
108static uint sector_offset = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000109
110/*
111 * Raw disk label. For DOS-type partition tables the MBR,
112 * with descriptions of the primary partitions.
113 */
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000114#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000115static char MBRbuffer[MAX_SECTOR_SIZE];
"Vladimir N. Oleynik"65bb10f2005-11-24 12:10:13 +0000116#else
117# define MBRbuffer bb_common_bufsiz1
118#endif
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000119
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000120#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000121static int sun_label; /* looking at sun disklabel */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000122#else
123#define sun_label 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000124#endif
125#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000126static int sgi_label; /* looking at sgi disklabel */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000127#else
128#define sgi_label 0
129#endif
130#ifdef CONFIG_FEATURE_AIX_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000131static int aix_label; /* looking at aix disklabel */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000132#else
133#define aix_label 0
134#endif
135#ifdef CONFIG_FEATURE_OSF_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +0000136static int osf_label; /* looking at OSF/1 disklabel */
137static int possibly_osf_label;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000138#else
139#define osf_label 0
140#endif
141
142#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
143
144static uint heads, sectors, cylinders;
145static void update_units(void);
146
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000147
148/*
149 * return partition name - uses static storage unless buf is supplied
150 */
151static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000152partname(const char *dev, int pno, int lth)
153{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000154 static char buffer[80];
155 const char *p;
156 int w, wp;
157 int bufsiz;
158 char *bufp;
159
160 bufp = buffer;
161 bufsiz = sizeof(buffer);
162
163 w = strlen(dev);
164 p = "";
165
166 if (isdigit(dev[w-1]))
167 p = "p";
168
169 /* devfs kludge - note: fdisk partition names are not supposed
170 to equal kernel names, so there is no reason to do this */
Rob Landleyb73451d2006-02-24 16:29:00 +0000171 if (strcmp(dev + w - 4, "disc") == 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000172 w -= 4;
173 p = "part";
174 }
175
176 wp = strlen(p);
177
178 if (lth) {
179 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
180 lth-wp-2, w, dev, p, pno);
181 } else {
182 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
183 }
184 return bufp;
185}
186
187struct partition {
188 unsigned char boot_ind; /* 0x80 - active */
189 unsigned char head; /* starting head */
190 unsigned char sector; /* starting sector */
191 unsigned char cyl; /* starting cylinder */
192 unsigned char sys_ind; /* What partition type */
193 unsigned char end_head; /* end head */
194 unsigned char end_sector; /* end sector */
195 unsigned char end_cyl; /* end cylinder */
196 unsigned char start4[4]; /* starting sector counting from 0 */
197 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000198} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000199
200enum failure {
201 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
202 unable_to_write
203};
204
Rob Landleyb73451d2006-02-24 16:29:00 +0000205enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000206
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000207static const char *disk_device;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000208static int fd; /* the disk */
209static int partitions = 4; /* maximum partition + 1 */
210static uint display_in_cyl_units = 1;
211static uint units_per_sector = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000212#ifdef CONFIG_FEATURE_FDISK_WRITABLE
213static char *line_ptr;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000214static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000215static void reread_partition_table(int leave);
216static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000217static int get_partition(int warn, int max);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000218static void list_types(const struct systypes *sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000219static uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000220#endif
221static const char *partition_type(unsigned char type);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000222static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000223static void get_geometry(void);
224static int get_boot(enum action what);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000225
226#define PLURAL 0
227#define SINGULAR 1
228
229#define hex_val(c) ({ \
230 char _c = (c); \
231 isdigit(_c) ? _c - '0' : \
232 tolower(_c) + 10 - 'a'; \
233 })
234
235
236#define LINE_LENGTH 800
237#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
238 (n) * sizeof(struct partition)))
239#define sector(s) ((s) & 0x3f)
240#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
241
242#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
243 ((h) + heads * cylinder(s,c)))
244#define set_hsc(h,s,c,sector) { \
245 s = sector % sectors + 1; \
246 sector /= sectors; \
247 h = sector % heads; \
248 sector /= heads; \
249 c = sector & 0xff; \
250 s |= (sector >> 2) & 0xc0; \
251 }
252
253
Eric Andersend9261492004-06-28 23:50:31 +0000254static int32_t get_start_sect(const struct partition *p);
255static int32_t get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000256
257/*
258 * per partition table entry data
259 *
260 * The four primary partitions have the same sectorbuffer (MBRbuffer)
261 * and have NULL ext_pointer.
262 * Each logical partition table entry has two pointers, one for the
263 * partition and one link to the next one.
264 */
265static struct pte {
266 struct partition *part_table; /* points into sectorbuffer */
267 struct partition *ext_pointer; /* points into sectorbuffer */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000268#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000269 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000270#endif
Eric Andersend9261492004-06-28 23:50:31 +0000271 off_t offset; /* disk sector number */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000272 char *sectorbuffer; /* disk sector contents */
273} ptes[MAXIMUM_PARTS];
274
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000275
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000276#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000277static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000278set_all_unchanged(void)
279{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000280 int i;
281
282 for (i = 0; i < MAXIMUM_PARTS; i++)
283 ptes[i].changed = 0;
284}
285
286static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000287set_changed(int i)
288{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000289 ptes[i].changed = 1;
290}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000291#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000292
293#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
294static struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000295get_part_table(int i)
296{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000297 return ptes[i].part_table;
298}
299#endif
300
301static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000302str_units(int n)
303{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000304 if (n == 1)
305 return display_in_cyl_units ? _("cylinder") : _("sector");
306 else
307 return display_in_cyl_units ? _("cylinders") : _("sectors");
308}
309
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000310static int
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +0000311valid_part_table_flag(const char *mbuffer) {
312 const unsigned char *b = (const unsigned char *)mbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000313 return (b[510] == 0x55 && b[511] == 0xaa);
314}
315
316#ifdef CONFIG_FEATURE_FDISK_WRITABLE
317static char line_buffer[LINE_LENGTH];
318
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000319/* read line; return 0 or first char */
320static int
321read_line(void)
322{
323 static int got_eof = 0;
324
325 fflush (stdout); /* requested by niles@scyld.com */
326 line_ptr = line_buffer;
327 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
328 if (feof(stdin))
329 got_eof++; /* user typed ^D ? */
330 if (got_eof >= 3) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000331 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
332 exit(1);
333 }
334 return 0;
335 }
336 while (*line_ptr && !isgraph(*line_ptr))
337 line_ptr++;
338 return *line_ptr;
339}
340
341static char
342read_char(const char *mesg)
343{
344 do {
345 fputs(mesg, stdout);
346 } while (!read_line());
347 return *line_ptr;
348}
349
350static char
351read_chars(const char *mesg)
352{
353 fputs(mesg, stdout);
354 if (!read_line()) {
355 *line_ptr = '\n';
356 line_ptr[1] = 0;
357 }
358 return *line_ptr;
359}
360
361static int
362read_hex(const struct systypes *sys)
363{
364 int hex;
365
Rob Landleyb73451d2006-02-24 16:29:00 +0000366 while (1) {
367 read_char(_("Hex code (type L to list codes): "));
368 if (*line_ptr == 'l' || *line_ptr == 'L')
369 list_types(sys);
370 else if (isxdigit (*line_ptr)) {
371 hex = 0;
372 do
373 hex = hex << 4 | hex_val(*line_ptr++);
374 while (isxdigit(*line_ptr));
375 return hex;
376 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000377 }
378}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000379#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000380
381#ifdef CONFIG_FEATURE_AIX_LABEL
382/*
383 * Copyright (C) Andreas Neuper, Sep 1998.
384 * This file may be redistributed under
385 * the terms of the GNU Public License.
386 */
387
388typedef struct {
389 unsigned int magic; /* expect AIX_LABEL_MAGIC */
390 unsigned int fillbytes1[124];
391 unsigned int physical_volume_id;
392 unsigned int fillbytes2[124];
393} aix_partition;
394
395#define AIX_LABEL_MAGIC 0xc9c2d4c1
396#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
397#define AIX_INFO_MAGIC 0x00072959
398#define AIX_INFO_MAGIC_SWAPPED 0x59290700
399
400#define aixlabel ((aix_partition *)MBRbuffer)
401
402
403/*
404 Changes:
Eric Andersen040f4402003-07-30 08:40:37 +0000405 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
406 * Internationalization
407 *
408 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
409 * Some fixes
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000410*/
411
Rob Landleyb73451d2006-02-24 16:29:00 +0000412static int aix_other_endian;
413static short aix_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000414
415/*
416 * only dealing with free blocks here
417 */
418
419static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000420aix_info(void)
421{
422 puts(
423 _("\n\tThere is a valid AIX label on this disk.\n"
424 "\tUnfortunately Linux cannot handle these\n"
425 "\tdisks at the moment. Nevertheless some\n"
426 "\tadvice:\n"
427 "\t1. fdisk will destroy its contents on write.\n"
428 "\t2. Be sure that this disk is NOT a still vital\n"
429 "\t part of a volume group. (Otherwise you may\n"
430 "\t erase the other disks as well, if unmirrored.)\n"
431 "\t3. Before deleting this physical volume be sure\n"
432 "\t to remove the disk logically from your AIX\n"
433 "\t machine. (Otherwise you become an AIXpert).")
434 );
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000435}
436
437static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000438aix_nolabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000439{
Rob Landleyb73451d2006-02-24 16:29:00 +0000440 aixlabel->magic = 0;
441 aix_label = 0;
442 partitions = 4;
443 memset(MBRbuffer, 0, sizeof(MBRbuffer)); /* avoid fdisk cores */
444 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000445}
446
447static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000448check_aix_label(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000449{
Rob Landleyb73451d2006-02-24 16:29:00 +0000450 if (aixlabel->magic != AIX_LABEL_MAGIC &&
451 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
452 aix_label = 0;
453 aix_other_endian = 0;
454 return 0;
455 }
456 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
457 update_units();
458 aix_label = 1;
459 partitions = 1016;
460 aix_volumes = 15;
461 aix_info();
462 aix_nolabel(); /* %% */
463 aix_label = 1; /* %% */
464 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000465}
466#endif /* AIX_LABEL */
467
468#ifdef CONFIG_FEATURE_OSF_LABEL
469/*
470 * Copyright (c) 1987, 1988 Regents of the University of California.
471 * All rights reserved.
472 *
473 * Redistribution and use in source and binary forms, with or without
474 * modification, are permitted provided that the following conditions
475 * are met:
476 * 1. Redistributions of source code must retain the above copyright
477 * notice, this list of conditions and the following disclaimer.
478 * 2. Redistributions in binary form must reproduce the above copyright
479 * notice, this list of conditions and the following disclaimer in the
480 * documentation and/or other materials provided with the distribution.
481 * 3. All advertising materials mentioning features or use of this software
Eric Andersenaff114c2004-04-14 17:51:38 +0000482 * must display the following acknowledgment:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000483 * This product includes software developed by the University of
484 * California, Berkeley and its contributors.
485 * 4. Neither the name of the University nor the names of its contributors
486 * may be used to endorse or promote products derived from this software
487 * without specific prior written permission.
488 *
489 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
490 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
491 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
492 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
493 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
494 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
495 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
496 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
497 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
498 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
499 * SUCH DAMAGE.
500 */
501
502
503#ifndef BSD_DISKMAGIC
Eric Andersenacd244a2002-12-11 03:49:33 +0000504#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000505#endif
506
507#ifndef BSD_MAXPARTITIONS
508#define BSD_MAXPARTITIONS 16
509#endif
510
511#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
512
513#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
514#define BSD_LABELSECTOR 1
515#define BSD_LABELOFFSET 0
516#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
517#define BSD_LABELSECTOR 0
518#define BSD_LABELOFFSET 64
Eric Andersen040f4402003-07-30 08:40:37 +0000519#elif defined (__s390__) || defined (__s390x__)
520#define BSD_LABELSECTOR 1
521#define BSD_LABELOFFSET 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000522#else
523#error unknown architecture
524#endif
525
526#define BSD_BBSIZE 8192 /* size of boot area, with label */
527#define BSD_SBSIZE 8192 /* max size of fs superblock */
528
529struct xbsd_disklabel {
Eric Andersenacd244a2002-12-11 03:49:33 +0000530 uint32_t d_magic; /* the magic number */
Rob Landleyb73451d2006-02-24 16:29:00 +0000531 int16_t d_type; /* drive type */
532 int16_t d_subtype; /* controller/d_type specific */
533 char d_typename[16]; /* type name, e.g. "eagle" */
534 char d_packname[16]; /* pack identifier */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000535 /* disk geometry: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000536 uint32_t d_secsize; /* # of bytes per sector */
537 uint32_t d_nsectors; /* # of data sectors per track */
538 uint32_t d_ntracks; /* # of tracks per cylinder */
539 uint32_t d_ncylinders; /* # of data cylinders per unit */
540 uint32_t d_secpercyl; /* # of data sectors per cylinder */
541 uint32_t d_secperunit; /* # of data sectors per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000542 /*
543 * Spares (bad sector replacements) below
544 * are not counted in d_nsectors or d_secpercyl.
545 * Spare sectors are assumed to be physical sectors
546 * which occupy space at the end of each track and/or cylinder.
547 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000548 uint16_t d_sparespertrack; /* # of spare sectors per track */
549 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000550 /*
551 * Alternate cylinders include maintenance, replacement,
552 * configuration description areas, etc.
553 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000554 uint32_t d_acylinders; /* # of alt. cylinders per unit */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000555
556 /* hardware characteristics: */
557 /*
558 * d_interleave, d_trackskew and d_cylskew describe perturbations
559 * in the media format used to compensate for a slow controller.
560 * Interleave is physical sector interleave, set up by the formatter
561 * or controller when formatting. When interleaving is in use,
562 * logically adjacent sectors are not physically contiguous,
563 * but instead are separated by some number of sectors.
564 * It is specified as the ratio of physical sectors traversed
565 * per logical sector. Thus an interleave of 1:1 implies contiguous
566 * layout, while 2:1 implies that logical sector 0 is separated
567 * by one sector from logical sector 1.
568 * d_trackskew is the offset of sector 0 on track N
569 * relative to sector 0 on track N-1 on the same cylinder.
570 * Finally, d_cylskew is the offset of sector 0 on cylinder N
571 * relative to sector 0 on cylinder N-1.
572 */
Eric Andersenacd244a2002-12-11 03:49:33 +0000573 uint16_t d_rpm; /* rotational speed */
574 uint16_t d_interleave; /* hardware sector interleave */
575 uint16_t d_trackskew; /* sector 0 skew, per track */
576 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
577 uint32_t d_headswitch; /* head switch time, usec */
578 uint32_t d_trkseek; /* track-to-track seek, usec */
579 uint32_t d_flags; /* generic flags */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000580#define NDDATA 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000581 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000582#define NSPARE 5
Eric Andersenacd244a2002-12-11 03:49:33 +0000583 uint32_t d_spare[NSPARE]; /* reserved for future use */
584 uint32_t d_magic2; /* the magic number (again) */
585 uint16_t d_checksum; /* xor of data incl. partitions */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000586 /* filesystem and partition information: */
Eric Andersenacd244a2002-12-11 03:49:33 +0000587 uint16_t d_npartitions; /* number of partitions in following */
588 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
589 uint32_t d_sbsize; /* max size of fs superblock, bytes */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000590 struct xbsd_partition { /* the partition table */
Eric Andersenacd244a2002-12-11 03:49:33 +0000591 uint32_t p_size; /* number of sectors in partition */
592 uint32_t p_offset; /* starting sector */
593 uint32_t p_fsize; /* filesystem basic fragment size */
594 uint8_t p_fstype; /* filesystem type, see below */
595 uint8_t p_frag; /* filesystem fragments per block */
596 uint16_t p_cpg; /* filesystem cylinders per group */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000597 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
598};
599
600/* d_type values: */
601#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
602#define BSD_DTYPE_MSCP 2 /* MSCP */
603#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
604#define BSD_DTYPE_SCSI 4 /* SCSI */
605#define BSD_DTYPE_ESDI 5 /* ESDI interface */
606#define BSD_DTYPE_ST506 6 /* ST506 etc. */
607#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
608#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
609#define BSD_DTYPE_FLOPPY 10 /* floppy */
610
611/* d_subtype values: */
612#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
613#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
614#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
615
616#ifdef DKTYPENAMES
617static const char * const xbsd_dktypenames[] = {
618 "unknown",
619 "SMD",
620 "MSCP",
621 "old DEC",
622 "SCSI",
623 "ESDI",
624 "ST506",
625 "HP-IB",
626 "HP-FL",
627 "type 9",
628 "floppy",
629 0
630};
631#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
632#endif
633
634/*
635 * Filesystem type and version.
636 * Used to interpret other filesystem-specific
637 * per-partition information.
638 */
639#define BSD_FS_UNUSED 0 /* unused */
640#define BSD_FS_SWAP 1 /* swap */
641#define BSD_FS_V6 2 /* Sixth Edition */
642#define BSD_FS_V7 3 /* Seventh Edition */
643#define BSD_FS_SYSV 4 /* System V */
644#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
645#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
646#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
647#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
648#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
649#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
650#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
651#define BSD_FS_ISOFS BSD_FS_ISO9660
652#define BSD_FS_BOOT 13 /* partition contains bootstrap */
653#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
654#define BSD_FS_HFS 15 /* Macintosh HFS */
655#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
656
657/* this is annoying, but it's also the way it is :-( */
658#ifdef __alpha__
659#define BSD_FS_EXT2 8 /* ext2 file system */
660#else
661#define BSD_FS_MSDOS 8 /* MS-DOS file system */
662#endif
663
664#ifdef DKTYPENAMES
665static const struct systypes xbsd_fstypes[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +0000666 { "\x00" "unused" }, /* BSD_FS_UNUSED */
667 { "\x01" "swap" }, /* BSD_FS_SWAP */
668 { "\x02" "Version 6" }, /* BSD_FS_V6 */
669 { "\x03" "Version 7" }, /* BSD_FS_V7 */
670 { "\x04" "System V" }, /* BSD_FS_SYSV */
671 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
672 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
673 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000674#ifdef __alpha__
Rob Landleyb73451d2006-02-24 16:29:00 +0000675 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000676#else
Rob Landleyb73451d2006-02-24 16:29:00 +0000677 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000678#endif
Rob Landleyb73451d2006-02-24 16:29:00 +0000679 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
680 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
681 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
682 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
683 { "\x0d" "boot" }, /* BSD_FS_BOOT */
684 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
685 { "\x0f" "HFS" }, /* BSD_FS_HFS */
686 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
687 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000688};
689#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
690
691#endif
692
693/*
694 * flags shared by various drives:
695 */
696#define BSD_D_REMOVABLE 0x01 /* removable media */
697#define BSD_D_ECC 0x02 /* supports ECC */
698#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
699#define BSD_D_RAMDISK 0x08 /* disk emulator */
700#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
701#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
702
703#endif /* OSF_LABEL */
704
705/*
706 * Copyright (C) Andreas Neuper, Sep 1998.
707 * This file may be modified and redistributed under
708 * the terms of the GNU Public License.
709 */
710
711struct device_parameter { /* 48 bytes */
712 unsigned char skew;
713 unsigned char gap1;
714 unsigned char gap2;
715 unsigned char sparecyl;
716 unsigned short pcylcount;
717 unsigned short head_vol0;
718 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
719 unsigned char cmd_tag_queue_depth;
720 unsigned char unused0;
721 unsigned short unused1;
722 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
723 unsigned short bytes;
724 unsigned short ilfact;
725 unsigned int flags; /* controller flags */
726 unsigned int datarate;
727 unsigned int retries_on_error;
728 unsigned int ms_per_word;
729 unsigned short xylogics_gap1;
730 unsigned short xylogics_syncdelay;
731 unsigned short xylogics_readdelay;
732 unsigned short xylogics_gap2;
733 unsigned short xylogics_readgate;
734 unsigned short xylogics_writecont;
735};
736
737#define SGI_VOLHDR 0x00
738/* 1 and 2 were used for drive types no longer supported by SGI */
739#define SGI_SWAP 0x03
740/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
741#define SGI_VOLUME 0x06
742#define SGI_EFS 0x07
743#define SGI_LVOL 0x08
744#define SGI_RLVOL 0x09
745#define SGI_XFS 0x0a
746#define SGI_XFSLOG 0x0b
747#define SGI_XLV 0x0c
748#define SGI_XVM 0x0d
749#define ENTIRE_DISK SGI_VOLUME
750/*
751 * controller flags
752 */
753#define SECTOR_SLIP 0x01
754#define SECTOR_FWD 0x02
755#define TRACK_FWD 0x04
756#define TRACK_MULTIVOL 0x08
757#define IGNORE_ERRORS 0x10
758#define RESEEK 0x20
759#define ENABLE_CMDTAGQ 0x40
760
761typedef struct {
762 unsigned int magic; /* expect SGI_LABEL_MAGIC */
763 unsigned short boot_part; /* active boot partition */
764 unsigned short swap_part; /* active swap partition */
765 unsigned char boot_file[16]; /* name of the bootfile */
766 struct device_parameter devparam; /* 1 * 48 bytes */
767 struct volume_directory { /* 15 * 16 bytes */
768 unsigned char vol_file_name[8]; /* a character array */
769 unsigned int vol_file_start; /* number of logical block */
770 unsigned int vol_file_size; /* number of bytes */
771 } directory[15];
772 struct sgi_partition { /* 16 * 12 bytes */
773 unsigned int num_sectors; /* number of blocks */
774 unsigned int start_sector; /* must be cylinder aligned */
775 unsigned int id;
776 } partitions[16];
777 unsigned int csum;
778 unsigned int fillbytes;
779} sgi_partition;
780
781typedef struct {
782 unsigned int magic; /* looks like a magic number */
783 unsigned int a2;
784 unsigned int a3;
785 unsigned int a4;
786 unsigned int b1;
787 unsigned short b2;
788 unsigned short b3;
789 unsigned int c[16];
790 unsigned short d[3];
791 unsigned char scsi_string[50];
792 unsigned char serial[137];
793 unsigned short check1816;
794 unsigned char installer[225];
795} sgiinfo;
796
797#define SGI_LABEL_MAGIC 0x0be5a941
798#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
799#define SGI_INFO_MAGIC 0x00072959
800#define SGI_INFO_MAGIC_SWAPPED 0x59290700
801#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000802 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000803#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000804 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000805
806#define sgilabel ((sgi_partition *)MBRbuffer)
807#define sgiparam (sgilabel->devparam)
808
809typedef struct {
810 unsigned char info[128]; /* Informative text string */
811 unsigned char spare0[14];
812 struct sun_info {
813 unsigned char spare1;
814 unsigned char id;
815 unsigned char spare2;
816 unsigned char flags;
817 } infos[8];
818 unsigned char spare1[246]; /* Boot information etc. */
819 unsigned short rspeed; /* Disk rotational speed */
820 unsigned short pcylcount; /* Physical cylinder count */
821 unsigned short sparecyl; /* extra sects per cylinder */
822 unsigned char spare2[4]; /* More magic... */
823 unsigned short ilfact; /* Interleave factor */
824 unsigned short ncyl; /* Data cylinder count */
825 unsigned short nacyl; /* Alt. cylinder count */
826 unsigned short ntrks; /* Tracks per cylinder */
827 unsigned short nsect; /* Sectors per track */
828 unsigned char spare3[4]; /* Even more magic... */
829 struct sun_partition {
Eric Andersenacd244a2002-12-11 03:49:33 +0000830 uint32_t start_cylinder;
831 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000832 } partitions[8];
833 unsigned short magic; /* Magic number */
834 unsigned short csum; /* Label xor'd checksum */
835} sun_partition;
836
Eric Andersen040f4402003-07-30 08:40:37 +0000837
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000838#define SUN_LABEL_MAGIC 0xDABE
839#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
840#define sunlabel ((sun_partition *)MBRbuffer)
841#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000842 : (uint16_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000843#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
Eric Andersenacd244a2002-12-11 03:49:33 +0000844 : (uint32_t)(x))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000845
Eric Andersend3652bf2003-08-06 09:07:37 +0000846
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000847#ifdef CONFIG_FEATURE_OSF_LABEL
848/*
849 Changes:
850 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
851
852 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
853 support for OSF/1 disklabels on Alpha.
854 Also fixed unaligned accesses in alpha_bootblock_checksum()
855*/
856
857#define FREEBSD_PARTITION 0xa5
858#define NETBSD_PARTITION 0xa9
859
Rob Landleyb73451d2006-02-24 16:29:00 +0000860static void xbsd_delete_part(void);
861static void xbsd_new_part(void);
862static void xbsd_write_disklabel(void);
863static int xbsd_create_disklabel(void);
864static void xbsd_edit_disklabel(void);
865static void xbsd_write_bootstrap(void);
866static void xbsd_change_fstype(void);
867static int xbsd_get_part_index(int max);
868static int xbsd_check_new_partition(int *i);
869static void xbsd_list_types(void);
870static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
871static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
872static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
873static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000874
875#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000876static void alpha_bootblock_checksum(char *boot);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000877#endif
878
879#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000880static int xbsd_translate_fstype(int linux_type);
881static void xbsd_link_part(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000882static struct partition *xbsd_part;
883static int xbsd_part_index;
884#endif
885
886#if defined (__alpha__)
Eric Andersendfcb5b02004-01-30 22:54:20 +0000887/* We access this through a uint64_t * when checksumming */
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +0000888static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000889#else
890static char disklabelbuffer[BSD_BBSIZE];
891#endif
892
893static struct xbsd_disklabel xbsd_dlabel;
894
895#define bsd_cround(n) \
896 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
897
898/*
899 * Test whether the whole disk has BSD disk label magic.
900 *
901 * Note: often reformatting with DOS-type label leaves the BSD magic,
902 * so this does not mean that there is a BSD disk label.
903 */
904static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000905check_osf_label(void)
906{
907 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000908 return 0;
909 return 1;
910}
911
912static void xbsd_print_disklabel(int);
913
914static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000915btrydev(const char * dev)
916{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000917 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
918 return -1;
919 printf(_("\nBSD label for device: %s\n"), dev);
920 xbsd_print_disklabel (0);
921 return 0;
922}
923
924static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000925bmenu(void)
926{
927 puts (_("Command action"));
928 puts (_("\td\tdelete a BSD partition"));
929 puts (_("\te\tedit drive data"));
930 puts (_("\ti\tinstall bootstrap"));
931 puts (_("\tl\tlist known filesystem types"));
932 puts (_("\tm\tprint this menu"));
933 puts (_("\tn\tadd a new BSD partition"));
934 puts (_("\tp\tprint BSD partition table"));
935 puts (_("\tq\tquit without saving changes"));
936 puts (_("\tr\treturn to main menu"));
937 puts (_("\ts\tshow complete disklabel"));
938 puts (_("\tt\tchange a partition's filesystem id"));
939 puts (_("\tu\tchange units (cylinders/sectors)"));
940 puts (_("\tw\twrite disklabel to disk"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000941#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000942 puts (_("\tx\tlink BSD partition to non-BSD partition"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000943#endif
944}
945
946#if !defined (__alpha__)
947static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000948hidden(int type)
949{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000950 return type ^ 0x10;
951}
952
953static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000954is_bsd_partition_type(int type)
955{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000956 return (type == FREEBSD_PARTITION ||
957 type == hidden(FREEBSD_PARTITION) ||
958 type == NETBSD_PARTITION ||
959 type == hidden(NETBSD_PARTITION));
960}
961#endif
962
963static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000964bselect(void)
965{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000966#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +0000967 int t, ss;
968 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000969
Rob Landleyb73451d2006-02-24 16:29:00 +0000970 for (t = 0; t < 4; t++) {
971 p = get_part_table(t);
972 if (p && is_bsd_partition_type(p->sys_ind)) {
973 xbsd_part = p;
974 xbsd_part_index = t;
975 ss = get_start_sect(xbsd_part);
976 if (ss == 0) {
977 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
978 partname(disk_device, t+1, 0));
979 return;
980 }
981 printf(_("Reading disklabel of %s at sector %d.\n"),
982 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
983 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
984 if (xbsd_create_disklabel() == 0)
985 return;
986 break;
987 }
988 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000989
Rob Landleyb73451d2006-02-24 16:29:00 +0000990 if (t == 4) {
991 printf(_("There is no *BSD partition on %s.\n"), disk_device);
992 return;
993 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000994
995#elif defined (__alpha__)
996
Rob Landleyb73451d2006-02-24 16:29:00 +0000997 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
998 if (xbsd_create_disklabel() == 0)
999 exit (EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001000
1001#endif
1002
Rob Landleyb73451d2006-02-24 16:29:00 +00001003 while (1) {
1004 putchar('\n');
1005 switch (tolower(read_char(_("BSD disklabel command (m for help): ")))) {
1006 case 'd':
1007 xbsd_delete_part();
1008 break;
1009 case 'e':
1010 xbsd_edit_disklabel();
1011 break;
1012 case 'i':
1013 xbsd_write_bootstrap();
1014 break;
1015 case 'l':
1016 xbsd_list_types();
1017 break;
1018 case 'n':
1019 xbsd_new_part();
1020 break;
1021 case 'p':
1022 xbsd_print_disklabel(0);
1023 break;
1024 case 'q':
1025 close(fd);
1026 exit(EXIT_SUCCESS);
1027 case 'r':
1028 return;
1029 case 's':
1030 xbsd_print_disklabel(1);
1031 break;
1032 case 't':
1033 xbsd_change_fstype();
1034 break;
1035 case 'u':
1036 change_units();
1037 break;
1038 case 'w':
1039 xbsd_write_disklabel();
1040 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001041#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001042 case 'x':
1043 xbsd_link_part();
1044 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001045#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001046 default:
1047 bmenu();
1048 break;
1049 }
1050 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001051}
1052
1053static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001054xbsd_delete_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001055{
Rob Landleyb73451d2006-02-24 16:29:00 +00001056 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001057
Rob Landleyb73451d2006-02-24 16:29:00 +00001058 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1059 xbsd_dlabel.d_partitions[i].p_size = 0;
1060 xbsd_dlabel.d_partitions[i].p_offset = 0;
1061 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
1062 if (xbsd_dlabel.d_npartitions == i + 1)
1063 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
1064 xbsd_dlabel.d_npartitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001065}
1066
1067static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001068xbsd_new_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001069{
Rob Landleyb73451d2006-02-24 16:29:00 +00001070 off_t begin, end;
1071 char mesg[256];
1072 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001073
Rob Landleyb73451d2006-02-24 16:29:00 +00001074 if (!xbsd_check_new_partition(&i))
1075 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001076
1077#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001078 begin = get_start_sect(xbsd_part);
1079 end = begin + get_nr_sects(xbsd_part) - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001080#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001081 begin = 0;
1082 end = xbsd_dlabel.d_secperunit - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001083#endif
1084
Rob Landleyb73451d2006-02-24 16:29:00 +00001085 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1086 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
1087 0, mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001088
Rob Landleyb73451d2006-02-24 16:29:00 +00001089 if (display_in_cyl_units)
1090 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001091
Rob Landleyb73451d2006-02-24 16:29:00 +00001092 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
1093 str_units(SINGULAR));
1094 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
1095 bsd_cround (begin), mesg);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001096
Rob Landleyb73451d2006-02-24 16:29:00 +00001097 if (display_in_cyl_units)
1098 end = end * xbsd_dlabel.d_secpercyl - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001099
Rob Landleyb73451d2006-02-24 16:29:00 +00001100 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
1101 xbsd_dlabel.d_partitions[i].p_offset = begin;
1102 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001103}
1104
1105static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001106xbsd_print_disklabel(int show_all)
1107{
1108 struct xbsd_disklabel *lp = &xbsd_dlabel;
1109 struct xbsd_partition *pp;
1110 int i, j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001111
Rob Landleyb73451d2006-02-24 16:29:00 +00001112 if (show_all) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001113#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001114 printf("# %s:\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001115#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001116 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001117#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001118 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
1119 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
1120 else
1121 printf(_("type: %d\n"), lp->d_type);
1122 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
1123 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
1124 printf(_("flags:"));
1125 if (lp->d_flags & BSD_D_REMOVABLE)
1126 printf(_(" removable"));
1127 if (lp->d_flags & BSD_D_ECC)
1128 printf(_(" ecc"));
1129 if (lp->d_flags & BSD_D_BADSECT)
1130 printf(_(" badsect"));
1131 printf("\n");
1132 /* On various machines the fields of *lp are short/int/long */
1133 /* In order to avoid problems, we cast them all to long. */
1134 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
1135 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
1136 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
1137 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
1138 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
1139 printf(_("rpm: %d\n"), lp->d_rpm);
1140 printf(_("interleave: %d\n"), lp->d_interleave);
1141 printf(_("trackskew: %d\n"), lp->d_trackskew);
1142 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
1143 printf(_("headswitch: %ld\t\t# milliseconds\n"),
1144 (long) lp->d_headswitch);
1145 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
1146 (long) lp->d_trkseek);
1147 printf(_("drivedata: "));
1148 for (i = NDDATA - 1; i >= 0; i--)
1149 if (lp->d_drivedata[i])
1150 break;
1151 if (i < 0)
1152 i = 0;
1153 for (j = 0; j <= i; j++)
1154 printf("%ld ", (long) lp->d_drivedata[j]);
1155 }
1156 printf(_("\n%d partitions:\n"), lp->d_npartitions);
1157 printf(_("# start end size fstype [fsize bsize cpg]\n"));
1158 pp = lp->d_partitions;
1159 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1160 if (pp->p_size) {
1161 if (display_in_cyl_units && lp->d_secpercyl) {
1162 printf(" %c: %8ld%c %8ld%c %8ld%c ",
1163 'a' + i,
1164 (long) pp->p_offset / lp->d_secpercyl + 1,
1165 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
1166 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
1167 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
1168 (long) pp->p_size / lp->d_secpercyl,
1169 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
1170 );
1171 } else {
1172 printf(" %c: %8ld %8ld %8ld ",
1173 'a' + i,
1174 (long) pp->p_offset,
1175 (long) pp->p_offset + pp->p_size - 1,
1176 (long) pp->p_size
1177 );
1178 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001179
Rob Landleyb73451d2006-02-24 16:29:00 +00001180 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
1181 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
1182 else
1183 printf("%8x", pp->p_fstype);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001184
Rob Landleyb73451d2006-02-24 16:29:00 +00001185 switch (pp->p_fstype) {
1186 case BSD_FS_UNUSED:
1187 printf(" %5ld %5ld %5.5s ",
1188 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
1189 break;
1190 case BSD_FS_BSDFFS:
1191 printf(" %5ld %5ld %5d ",
1192 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
1193 break;
1194 default:
1195 printf("%22.22s", "");
1196 break;
1197 }
1198 printf("\n");
1199 }
1200 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001201}
1202
1203static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001204xbsd_write_disklabel(void)
1205{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001206#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001207 printf(_("Writing disklabel to %s.\n"), disk_device);
1208 xbsd_writelabel(NULL, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001209#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001210 printf(_("Writing disklabel to %s.\n"),
1211 partname(disk_device, xbsd_part_index + 1, 0));
1212 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001213#endif
1214 reread_partition_table(0); /* no exit yet */
1215}
1216
1217static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001218xbsd_create_disklabel(void)
1219{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001220 char c;
1221
1222#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001223 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001224#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001225 fprintf(stderr, _("%s contains no disklabel.\n"),
1226 partname(disk_device, xbsd_part_index + 1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001227#endif
1228
1229 while (1) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001230 c = read_char(_("Do you want to create a disklabel? (y/n) "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001231 if (c == 'y' || c == 'Y') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001232 if (xbsd_initlabel(
Eric Andersen040f4402003-07-30 08:40:37 +00001233#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
Rob Landleyb73451d2006-02-24 16:29:00 +00001234 defined (__s390__) || defined (__s390x__)
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001235 NULL, &xbsd_dlabel
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001236#else
Bernhard Reutner-Fischer9f4a1e12006-01-31 09:53:53 +00001237 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001238#endif
1239 ) == 1) {
1240 xbsd_print_disklabel (1);
1241 return 1;
1242 } else
1243 return 0;
1244 } else if (c == 'n')
1245 return 0;
1246 }
1247}
1248
1249static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001250edit_int(int def, char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001251{
Rob Landleyb73451d2006-02-24 16:29:00 +00001252 do {
1253 fputs(mesg, stdout);
1254 printf(" (%d): ", def);
1255 if (!read_line())
1256 return def;
1257 }
1258 while (!isdigit(*line_ptr)); /* FIXME: ?!! */
1259 return atoi(line_ptr);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001260}
1261
1262static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001263xbsd_edit_disklabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001264{
Rob Landleyb73451d2006-02-24 16:29:00 +00001265 struct xbsd_disklabel *d;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001266
Rob Landleyb73451d2006-02-24 16:29:00 +00001267 d = &xbsd_dlabel;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001268
1269#if defined (__alpha__) || defined (__ia64__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001270 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
1271 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
1272 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
1273 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001274#endif
1275
Rob Landleyb73451d2006-02-24 16:29:00 +00001276 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
1277 while (1) {
1278 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
1279 _("sectors/cylinder"));
1280 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
1281 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001282
Rob Landleyb73451d2006-02-24 16:29:00 +00001283 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
1284 }
1285 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
1286 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
1287 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
1288 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
1289 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
1290 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291
Rob Landleyb73451d2006-02-24 16:29:00 +00001292 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001293}
1294
1295static int
1296xbsd_get_bootstrap (char *path, void *ptr, int size)
1297{
Rob Landleyb73451d2006-02-24 16:29:00 +00001298 int fdb;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001299
Rob Landleyb73451d2006-02-24 16:29:00 +00001300 if ((fdb = open (path, O_RDONLY)) < 0) {
1301 perror(path);
1302 return 0;
1303 }
1304 if (read(fdb, ptr, size) < 0) {
1305 perror(path);
1306 close(fdb);
1307 return 0;
1308 }
1309 printf(" ... %s\n", path);
1310 close(fdb);
1311 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001312}
1313
1314static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001315sync_disks(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001316{
Rob Landleyb73451d2006-02-24 16:29:00 +00001317 printf(_("\nSyncing disks.\n"));
1318 sync();
1319 sleep(4); /* What? */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001320}
1321
1322static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001323xbsd_write_bootstrap(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001324{
Rob Landleyb73451d2006-02-24 16:29:00 +00001325 char *bootdir = BSD_LINUX_BOOTDIR;
1326 char path[MAXPATHLEN];
1327 char *dkbasename;
1328 struct xbsd_disklabel dl;
1329 char *d, *p, *e;
1330 int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001331
Rob Landleyb73451d2006-02-24 16:29:00 +00001332 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
1333 dkbasename = "sd";
1334 else
1335 dkbasename = "wd";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001336
Rob Landleyb73451d2006-02-24 16:29:00 +00001337 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
1338 dkbasename, dkbasename, dkbasename);
1339 if (read_line()) {
1340 line_ptr[strlen(line_ptr)-1] = '\0';
1341 dkbasename = line_ptr;
1342 }
1343 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
1344 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
1345 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001346
Rob Landleyb73451d2006-02-24 16:29:00 +00001347/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
1348 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
1349 bcopy(d, &dl, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001350
Rob Landleyb73451d2006-02-24 16:29:00 +00001351/* The disklabel will be overwritten by 0's from bootxx anyway */
1352 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001353
Rob Landleyb73451d2006-02-24 16:29:00 +00001354 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
1355 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize],
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001356 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
Rob Landleyb73451d2006-02-24 16:29:00 +00001357 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001358
Rob Landleyb73451d2006-02-24 16:29:00 +00001359 e = d + sizeof(struct xbsd_disklabel);
1360 for (p = d; p < e; p++)
1361 if (*p) {
1362 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
1363 exit(EXIT_FAILURE);
1364 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001365
Rob Landleyb73451d2006-02-24 16:29:00 +00001366 bcopy(&dl, d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001367
1368#if defined (__powerpc__) || defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001369 sector = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001370#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001371 sector = 0;
1372 alpha_bootblock_checksum(disklabelbuffer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001374 sector = get_start_sect(xbsd_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001375#endif
1376
Rob Landleyb73451d2006-02-24 16:29:00 +00001377 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1378 fdisk_fatal(unable_to_seek);
1379 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1380 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001381
1382#if defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001383 printf(_("Bootstrap installed on %s.\n"), disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001384#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001385 printf(_("Bootstrap installed on %s.\n"),
1386 partname (disk_device, xbsd_part_index+1, 0));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001387#endif
1388
Rob Landleyb73451d2006-02-24 16:29:00 +00001389 sync_disks();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001390}
1391
1392static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001393xbsd_change_fstype(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001394{
Rob Landleyb73451d2006-02-24 16:29:00 +00001395 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001396
Rob Landleyb73451d2006-02-24 16:29:00 +00001397 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
1398 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001399}
1400
1401static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001402xbsd_get_part_index(int max)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001403{
Rob Landleyb73451d2006-02-24 16:29:00 +00001404 char prompt[256];
1405 char l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001406
Rob Landleyb73451d2006-02-24 16:29:00 +00001407 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
1408 do
1409 l = tolower(read_char(prompt));
1410 while (l < 'a' || l > 'a' + max - 1);
1411 return l - 'a';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001412}
1413
1414static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001415xbsd_check_new_partition(int *i)
1416{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001417 /* room for more? various BSD flavours have different maxima */
1418 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
1419 int t;
1420
1421 for (t = 0; t < BSD_MAXPARTITIONS; t++)
1422 if (xbsd_dlabel.d_partitions[t].p_size == 0)
1423 break;
1424
1425 if (t == BSD_MAXPARTITIONS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001426 fprintf(stderr, _("The maximum number of partitions "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001427 "has been created\n"));
1428 return 0;
1429 }
1430 }
1431
1432 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
1433
1434 if (*i >= xbsd_dlabel.d_npartitions)
1435 xbsd_dlabel.d_npartitions = (*i) + 1;
1436
1437 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001438 fprintf(stderr, _("This partition already exists.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001439 return 0;
1440 }
1441
1442 return 1;
1443}
1444
1445static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001446xbsd_list_types(void)
1447{
1448 list_types(xbsd_fstypes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001449}
1450
1451static u_short
Rob Landleyb73451d2006-02-24 16:29:00 +00001452xbsd_dkcksum(struct xbsd_disklabel *lp)
1453{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001454 u_short *start, *end;
1455 u_short sum = 0;
1456
1457 start = (u_short *) lp;
1458 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
1459 while (start < end)
1460 sum ^= *start++;
1461 return sum;
1462}
1463
1464static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001465xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
1466{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001467 struct xbsd_partition *pp;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001468
Rob Landleyb73451d2006-02-24 16:29:00 +00001469 get_geometry();
1470 memset(d, 0, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001471
Rob Landleyb73451d2006-02-24 16:29:00 +00001472 d->d_magic = BSD_DISKMAGIC;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001473
Rob Landleyb73451d2006-02-24 16:29:00 +00001474 if (strncmp(disk_device, "/dev/sd", 7) == 0)
1475 d->d_type = BSD_DTYPE_SCSI;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001476 else
Rob Landleyb73451d2006-02-24 16:29:00 +00001477 d->d_type = BSD_DTYPE_ST506;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001478
1479#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
Rob Landleyb73451d2006-02-24 16:29:00 +00001480 d->d_subtype = BSD_DSTYPE_INDOSPART & pindex;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001481#endif
1482
1483#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001484 d->d_flags = BSD_D_DOSPART;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001485#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001486 d->d_flags = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001487#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001488 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
1489 d->d_nsectors = sectors; /* sectors/track */
1490 d->d_ntracks = heads; /* tracks/cylinder (heads) */
1491 d->d_ncylinders = cylinders;
1492 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
1493 if (d->d_secpercyl == 0)
1494 d->d_secpercyl = 1; /* avoid segfaults */
1495 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001496
Rob Landleyb73451d2006-02-24 16:29:00 +00001497 d->d_rpm = 3600;
1498 d->d_interleave = 1;
1499 d->d_trackskew = 0;
1500 d->d_cylskew = 0;
1501 d->d_headswitch = 0;
1502 d->d_trkseek = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001503
Rob Landleyb73451d2006-02-24 16:29:00 +00001504 d->d_magic2 = BSD_DISKMAGIC;
1505 d->d_bbsize = BSD_BBSIZE;
1506 d->d_sbsize = BSD_SBSIZE;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001507
1508#if !defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001509 d->d_npartitions = 4;
1510 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001511 the NetBSD partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00001512 pp->p_offset = get_start_sect(p);
1513 pp->p_size = get_nr_sects(p);
1514 pp->p_fstype = BSD_FS_UNUSED;
1515 pp = &d->d_partitions[3]; /* Partition D should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001516 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001517 pp->p_offset = 0;
1518 pp->p_size = d->d_secperunit;
1519 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001520#elif defined (__alpha__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001521 d->d_npartitions = 3;
1522 pp = &d->d_partitions[2]; /* Partition C should be
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001523 the whole disk */
Rob Landleyb73451d2006-02-24 16:29:00 +00001524 pp->p_offset = 0;
1525 pp->p_size = d->d_secperunit;
1526 pp->p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001527#endif
1528
1529 return 1;
1530}
1531
1532/*
1533 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
1534 * If it has the right magic, return 1.
1535 */
1536static int
1537xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
1538{
1539 int t, sector;
1540
1541 /* p is used only to get the starting sector */
1542#if !defined (__alpha__)
1543 sector = (p ? get_start_sect(p) : 0);
1544#elif defined (__alpha__)
1545 sector = 0;
1546#endif
1547
Rob Landleyb73451d2006-02-24 16:29:00 +00001548 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
1549 fdisk_fatal(unable_to_seek);
1550 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
1551 fdisk_fatal(unable_to_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001552
Rob Landleyb73451d2006-02-24 16:29:00 +00001553 bcopy(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1554 d, sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001555
Rob Landleyb73451d2006-02-24 16:29:00 +00001556 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001557 return 0;
1558
Rob Landleyb73451d2006-02-24 16:29:00 +00001559 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
1560 d->d_partitions[t].p_size = 0;
1561 d->d_partitions[t].p_offset = 0;
1562 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001563 }
1564
Rob Landleyb73451d2006-02-24 16:29:00 +00001565 if (d->d_npartitions > BSD_MAXPARTITIONS)
1566 fprintf(stderr, _("Warning: too many partitions "
1567 "(%d, maximum is %d).\n"),
1568 d->d_npartitions, BSD_MAXPARTITIONS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001569 return 1;
1570}
1571
1572static int
1573xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
1574{
Rob Landleyb73451d2006-02-24 16:29:00 +00001575 unsigned int sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001576
1577#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
Rob Landleyb73451d2006-02-24 16:29:00 +00001578 sector = get_start_sect(p) + BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001579#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001580 sector = BSD_LABELSECTOR;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001581#endif
1582
Rob Landleyb73451d2006-02-24 16:29:00 +00001583 d->d_checksum = 0;
1584 d->d_checksum = xbsd_dkcksum (d);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001585
Rob Landleyb73451d2006-02-24 16:29:00 +00001586 /* This is necessary if we want to write the bootstrap later,
1587 otherwise we'd write the old disklabel with the bootstrap.
1588 */
1589 bcopy(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
1590 sizeof(struct xbsd_disklabel));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001591
1592#if defined (__alpha__) && BSD_LABELSECTOR == 0
Rob Landleyb73451d2006-02-24 16:29:00 +00001593 alpha_bootblock_checksum (disklabelbuffer);
1594 if (lseek(fd, 0, SEEK_SET) == -1)
1595 fdisk_fatal(unable_to_seek);
1596 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
1597 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001598#else
Rob Landleyb73451d2006-02-24 16:29:00 +00001599 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
1600 fdisk_fatal(unable_to_seek);
1601 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
1602 fdisk_fatal(unable_to_write);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001603#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001604 sync_disks();
1605 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001606}
1607
1608
1609#if !defined (__alpha__)
1610static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001611xbsd_translate_fstype(int linux_type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001612{
Rob Landleyb73451d2006-02-24 16:29:00 +00001613 switch (linux_type) {
1614 case 0x01: /* DOS 12-bit FAT */
1615 case 0x04: /* DOS 16-bit <32M */
1616 case 0x06: /* DOS 16-bit >=32M */
1617 case 0xe1: /* DOS access */
1618 case 0xe3: /* DOS R/O */
1619 case 0xf2: /* DOS secondary */
1620 return BSD_FS_MSDOS;
1621 case 0x07: /* OS/2 HPFS */
1622 return BSD_FS_HPFS;
1623 default:
1624 return BSD_FS_OTHER;
1625 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001626}
1627
1628static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001629xbsd_link_part(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001630{
Rob Landleyb73451d2006-02-24 16:29:00 +00001631 int k, i;
1632 struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001633
Rob Landleyb73451d2006-02-24 16:29:00 +00001634 k = get_partition(1, partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001635
Rob Landleyb73451d2006-02-24 16:29:00 +00001636 if (!xbsd_check_new_partition(&i))
1637 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001638
Rob Landleyb73451d2006-02-24 16:29:00 +00001639 p = get_part_table(k);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001640
Rob Landleyb73451d2006-02-24 16:29:00 +00001641 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1642 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1643 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001644}
1645#endif
1646
1647#if defined (__alpha__)
1648
1649#if !defined(__GLIBC__)
Eric Andersendfcb5b02004-01-30 22:54:20 +00001650typedef unsigned long long uint64_t;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001651#endif
1652
1653static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001654alpha_bootblock_checksum(char *boot)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001655{
Rob Landleyb73451d2006-02-24 16:29:00 +00001656 uint64_t *dp, sum;
1657 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001658
Rob Landleyb73451d2006-02-24 16:29:00 +00001659 dp = (uint64_t *)boot;
1660 sum = 0;
1661 for (i = 0; i < 63; i++)
1662 sum += dp[i];
1663 dp[63] = sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001664}
1665#endif /* __alpha__ */
1666
1667#endif /* OSF_LABEL */
1668
1669#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
1670static inline unsigned short
Rob Landleyb73451d2006-02-24 16:29:00 +00001671__swap16(unsigned short x)
1672{
Eric Andersenacd244a2002-12-11 03:49:33 +00001673 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001674}
1675
Eric Andersenacd244a2002-12-11 03:49:33 +00001676static inline uint32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00001677__swap32(uint32_t x)
1678{
1679 return (((x & 0xFF) << 24) |
Eric Andersen040f4402003-07-30 08:40:37 +00001680 ((x & 0xFF00) << 8) |
1681 ((x & 0xFF0000) >> 8) |
1682 ((x & 0xFF000000) >> 24));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001683}
1684#endif
1685
1686#ifdef CONFIG_FEATURE_SGI_LABEL
1687/*
1688 *
1689 * fdisksgilabel.c
1690 *
1691 * Copyright (C) Andreas Neuper, Sep 1998.
1692 * This file may be modified and redistributed under
1693 * the terms of the GNU Public License.
1694 *
1695 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
1696 * Internationalization
1697 */
1698
1699
Rob Landleyb73451d2006-02-24 16:29:00 +00001700static int sgi_other_endian;
1701static int debug;
1702static short sgi_volumes = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001703
1704/*
1705 * only dealing with free blocks here
1706 */
1707
Rob Landleyb73451d2006-02-24 16:29:00 +00001708typedef struct {
1709 unsigned int first;
1710 unsigned int last;
1711} freeblocks;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001712static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
1713
1714static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001715setfreelist(int i, unsigned int f, unsigned int l)
1716{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001717 freelist[i].first = f;
1718 freelist[i].last = l;
1719}
1720
1721static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001722add2freelist(unsigned int f, unsigned int l)
1723{
1724 int i;
1725 for (i = 0; i < 17 ; i++)
Eric Andersen040f4402003-07-30 08:40:37 +00001726 if (freelist[i].last == 0)
1727 break;
1728 setfreelist(i, f, l);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001729}
1730
1731static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001732clearfreelist(void)
1733{
Eric Andersen040f4402003-07-30 08:40:37 +00001734 int i;
1735
1736 for (i = 0; i < 17 ; i++)
1737 setfreelist(i, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001738}
1739
Eric Andersen040f4402003-07-30 08:40:37 +00001740static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001741isinfreelist(unsigned int b)
1742{
Eric Andersen040f4402003-07-30 08:40:37 +00001743 int i;
1744
1745 for (i = 0; i < 17 ; i++)
1746 if (freelist[i].first <= b && freelist[i].last >= b)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001747 return freelist[i].last;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001748 return 0;
1749}
1750 /* return last vacant block of this stride (never 0). */
1751 /* the '>=' is not quite correct, but simplifies the code */
1752/*
1753 * end of free blocks section
1754 */
1755
1756static const struct systypes sgi_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00001757/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
1758/* 0x01 */ { "\x01" "SGI trkrepl" },
1759/* 0x02 */ { "\x02" "SGI secrepl" },
1760/* SGI_SWAP */ { "\x03" "SGI raw" },
1761/* 0x04 */ { "\x04" "SGI bsd" },
1762/* 0x05 */ { "\x05" "SGI sysv" },
1763/* ENTIRE_DISK */ { "\x06" "SGI volume" },
1764/* SGI_EFS */ { "\x07" "SGI efs" },
1765/* 0x08 */ { "\x08" "SGI lvol" },
1766/* 0x09 */ { "\x09" "SGI rlvol" },
1767/* SGI_XFS */ { "\x0a" "SGI xfs" },
1768/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
1769/* SGI_XLV */ { "\x0c" "SGI xlv" },
1770/* SGI_XVM */ { "\x0d" "SGI xvm" },
1771/* LINUX_SWAP */ { "\x82" "Linux swap" },
1772/* LINUX_NATIVE */ { "\x83" "Linux native" },
1773/* LINUX_LVM */ { "\x8d" "Linux LVM" },
1774/* LINUX_RAID */ { "\xfd" "Linux RAID" },
1775 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001776};
1777
1778
1779static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001780sgi_get_nsect(void)
1781{
1782 return SGI_SSWAP16(sgilabel->devparam.nsect);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001783}
1784
1785static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001786sgi_get_ntrks(void)
1787{
1788 return SGI_SSWAP16(sgilabel->devparam.ntrks);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001789}
1790
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001791static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001792sgi_nolabel(void)
1793{
1794 sgilabel->magic = 0;
1795 sgi_label = 0;
1796 partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001797}
1798
1799static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001800two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
1801{
1802 int i = 0;
1803 unsigned int sum = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001804
Rob Landleyb73451d2006-02-24 16:29:00 +00001805 size /= sizeof(unsigned int);
1806 for (i = 0; i < size; i++)
1807 sum -= SGI_SSWAP32(base[i]);
1808 return sum;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001809}
1810
1811static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001812check_sgi_label(void)
1813{
1814 if (sizeof(sgilabel) > 512) {
1815 fprintf(stderr,
1816 _("According to MIPS Computer Systems, Inc the "
1817 "Label must not contain more than 512 bytes\n"));
1818 exit(1);
1819 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001820
Rob Landleyb73451d2006-02-24 16:29:00 +00001821 if (sgilabel->magic != SGI_LABEL_MAGIC
1822 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
1823 sgi_label = 0;
1824 sgi_other_endian = 0;
1825 return 0;
1826 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001827
Rob Landleyb73451d2006-02-24 16:29:00 +00001828 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
1829 /*
1830 * test for correct checksum
1831 */
1832 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
1833 sizeof(*sgilabel))) {
Eric Andersen040f4402003-07-30 08:40:37 +00001834 fprintf(stderr,
1835 _("Detected sgi disklabel with wrong checksum.\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001836 }
1837 update_units();
1838 sgi_label = 1;
1839 partitions = 16;
1840 sgi_volumes = 15;
1841 return 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001842}
1843
Eric Andersen040f4402003-07-30 08:40:37 +00001844static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001845sgi_get_start_sector(int i)
1846{
1847 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001848}
1849
Eric Andersen040f4402003-07-30 08:40:37 +00001850static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001851sgi_get_num_sectors(int i)
1852{
1853 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001854}
1855
1856static int
Eric Andersen040f4402003-07-30 08:40:37 +00001857sgi_get_sysid(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001858{
Rob Landleyb73451d2006-02-24 16:29:00 +00001859 return SGI_SSWAP32(sgilabel->partitions[i].id);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001860}
1861
1862static int
1863sgi_get_bootpartition(void)
1864{
Rob Landleyb73451d2006-02-24 16:29:00 +00001865 return SGI_SSWAP16(sgilabel->boot_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001866}
1867
1868static int
1869sgi_get_swappartition(void)
1870{
Rob Landleyb73451d2006-02-24 16:29:00 +00001871 return SGI_SSWAP16(sgilabel->swap_part);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001872}
1873
1874static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001875sgi_list_table(int xtra)
1876{
1877 int i, w, wd;
1878 int kpi = 0; /* kernel partition ID */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001879
Rob Landleyb73451d2006-02-24 16:29:00 +00001880 if(xtra) {
1881 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
1882 "%d cylinders, %d physical cylinders\n"
1883 "%d extra sects/cyl, interleave %d:1\n"
1884 "%s\n"
1885 "Units = %s of %d * 512 bytes\n\n"),
1886 disk_device, heads, sectors, cylinders,
1887 SGI_SSWAP16(sgiparam.pcylcount),
1888 SGI_SSWAP16(sgiparam.sparecyl),
1889 SGI_SSWAP16(sgiparam.ilfact),
1890 (char *)sgilabel,
1891 str_units(PLURAL), units_per_sector);
1892 } else {
1893 printf( _("\nDisk %s (SGI disk label): "
1894 "%d heads, %d sectors, %d cylinders\n"
1895 "Units = %s of %d * 512 bytes\n\n"),
1896 disk_device, heads, sectors, cylinders,
1897 str_units(PLURAL), units_per_sector );
1898 }
Eric Andersen99a75d12003-08-08 20:04:56 +00001899
Rob Landleyb73451d2006-02-24 16:29:00 +00001900 w = strlen(disk_device);
1901 wd = strlen(_("Device"));
1902 if (w < wd)
Eric Andersen99a75d12003-08-08 20:04:56 +00001903 w = wd;
1904
Rob Landleyb73451d2006-02-24 16:29:00 +00001905 printf(_("----- partitions -----\n"
1906 "Pt# %*s Info Start End Sectors Id System\n"),
1907 w + 2, _("Device"));
1908 for (i = 0 ; i < partitions; i++) {
1909 if( sgi_get_num_sectors(i) || debug ) {
1910 uint32_t start = sgi_get_start_sector(i);
1911 uint32_t len = sgi_get_num_sectors(i);
1912 kpi++; /* only count nonempty partitions */
1913 printf(
1914 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
1915/* fdisk part number */ i+1,
1916/* device */ partname(disk_device, kpi, w+3),
1917/* flags */ (sgi_get_swappartition() == i) ? "swap" :
1918/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
1919/* start */ (long) scround(start),
1920/* end */ (long) scround(start+len)-1,
1921/* no odd flag on end */(long) len,
1922/* type id */ sgi_get_sysid(i),
1923/* type name */ partition_type(sgi_get_sysid(i)));
1924 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001925 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001926 printf(_("----- Bootinfo -----\nBootfile: %s\n"
1927 "----- Directory Entries -----\n"),
1928 sgilabel->boot_file);
Eric Andersen040f4402003-07-30 08:40:37 +00001929 for (i = 0 ; i < sgi_volumes; i++) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001930 if (sgilabel->directory[i].vol_file_size) {
1931 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
1932 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
1933 unsigned char *name = sgilabel->directory[i].vol_file_name;
Eric Andersen040f4402003-07-30 08:40:37 +00001934
Rob Landleyb73451d2006-02-24 16:29:00 +00001935 printf(_("%2d: %-10s sector%5u size%8u\n"),
1936 i, (char*)name, (unsigned int) start, (unsigned int) len);
1937 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001938 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001939}
1940
1941static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001942sgi_set_bootpartition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001943{
Rob Landleyb73451d2006-02-24 16:29:00 +00001944 sgilabel->boot_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001945}
1946
Eric Andersen040f4402003-07-30 08:40:37 +00001947static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00001948sgi_get_lastblock(void)
1949{
1950 return heads * sectors * cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001951}
1952
1953static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001954sgi_set_swappartition(int i)
1955{
1956 sgilabel->swap_part = SGI_SSWAP16(((short)i));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001957}
1958
1959static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001960sgi_check_bootfile(const char* aFile)
1961{
1962 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
1963 printf(_("\nInvalid Bootfile!\n"
1964 "\tThe bootfile must be an absolute non-zero pathname,\n"
1965 "\te.g. \"/unix\" or \"/unix.save\".\n"));
1966 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001967 } else {
1968 if (strlen(aFile) > 16) {
1969 printf(_("\n\tName of Bootfile too long: "
Rob Landleyb73451d2006-02-24 16:29:00 +00001970 "16 bytes maximum.\n"));
1971 return 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001972 } else {
1973 if (aFile[0] != '/') {
1974 printf(_("\n\tBootfile must have a "
Rob Landleyb73451d2006-02-24 16:29:00 +00001975 "fully qualified pathname.\n"));
1976 return 0;
1977 }
Eric Andersen040f4402003-07-30 08:40:37 +00001978 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001979 }
Eric Andersen3496fdc2006-01-30 23:09:20 +00001980 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
Eric Andersen040f4402003-07-30 08:40:37 +00001981 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
1982 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
Rob Landleyb73451d2006-02-24 16:29:00 +00001983 /* filename is correct and did change */
1984 return 1;
1985 }
1986 return 0; /* filename did not change */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001987}
1988
1989static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +00001990sgi_get_bootfile(void)
1991{
Eric Andersen3496fdc2006-01-30 23:09:20 +00001992 return (char*)sgilabel->boot_file;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001993}
1994
1995static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001996sgi_set_bootfile(const char* aFile)
1997{
1998 int i = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00001999
Rob Landleyb73451d2006-02-24 16:29:00 +00002000 if (sgi_check_bootfile(aFile)) {
2001 while (i < 16) {
2002 if ((aFile[i] != '\n') /* in principle caught again by next line */
2003 && (strlen(aFile) > i))
2004 sgilabel->boot_file[i] = aFile[i];
2005 else
2006 sgilabel->boot_file[i] = 0;
2007 i++;
2008 }
2009 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002010 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002011}
2012
2013static void
2014create_sgiinfo(void)
2015{
Rob Landleyb73451d2006-02-24 16:29:00 +00002016 /* I keep SGI's habit to write the sgilabel to the second block */
2017 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
2018 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
2019 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002020}
2021
Eric Andersen040f4402003-07-30 08:40:37 +00002022static sgiinfo *fill_sgiinfo(void);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002023
2024static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002025sgi_write_table(void)
2026{
2027 sgilabel->csum = 0;
2028 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
2029 (unsigned int*)sgilabel, sizeof(*sgilabel)));
2030 assert(two_s_complement_32bit_sum(
Eric Andersen040f4402003-07-30 08:40:37 +00002031 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
Rob Landleyb73451d2006-02-24 16:29:00 +00002032
2033 if (lseek(fd, 0, SEEK_SET) < 0)
2034 fdisk_fatal(unable_to_seek);
2035 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
2036 fdisk_fatal(unable_to_write);
2037 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
2038 /*
2039 * keep this habit of first writing the "sgilabel".
2040 * I never tested whether it works without (AN 981002).
2041 */
2042 sgiinfo *info = fill_sgiinfo();
2043 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
2044 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
2045 fdisk_fatal(unable_to_seek);
2046 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
2047 fdisk_fatal(unable_to_write);
2048 free(info);
2049 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002050}
2051
2052static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002053compare_start(int *x, int *y)
2054{
2055 /*
2056 * sort according to start sectors
2057 * and prefers largest partition:
2058 * entry zero is entire disk entry
2059 */
2060 unsigned int i = *x;
2061 unsigned int j = *y;
2062 unsigned int a = sgi_get_start_sector(i);
2063 unsigned int b = sgi_get_start_sector(j);
2064 unsigned int c = sgi_get_num_sectors(i);
2065 unsigned int d = sgi_get_num_sectors(j);
Eric Andersen040f4402003-07-30 08:40:37 +00002066
Rob Landleyb73451d2006-02-24 16:29:00 +00002067 if (a == b)
2068 return (d > c) ? 1 : (d == c) ? 0 : -1;
2069 return (a > b) ? 1 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002070}
2071
2072
2073static int
Eric Andersen040f4402003-07-30 08:40:37 +00002074verify_sgi(int verbose)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002075{
Rob Landleyb73451d2006-02-24 16:29:00 +00002076 int Index[16]; /* list of valid partitions */
2077 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
2078 int entire = 0, i = 0;
2079 unsigned int start = 0;
2080 long long gap = 0; /* count unused blocks */
2081 unsigned int lastblock = sgi_get_lastblock();
Eric Andersen040f4402003-07-30 08:40:37 +00002082
Rob Landleyb73451d2006-02-24 16:29:00 +00002083 clearfreelist();
2084 for (i = 0; i < 16; i++) {
2085 if (sgi_get_num_sectors(i) != 0) {
2086 Index[sortcount++] = i;
2087 if (sgi_get_sysid(i) == ENTIRE_DISK) {
2088 if (entire++ == 1) {
2089 if (verbose)
2090 printf(_("More than one entire disk entry present.\n"));
2091 }
2092 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002093 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002094 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002095 if (sortcount == 0) {
2096 if (verbose)
2097 printf(_("No partitions defined\n"));
2098 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
2099 }
2100 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
2101 if (sgi_get_sysid(Index[0]) == ENTIRE_DISK) {
2102 if ((Index[0] != 10) && verbose)
2103 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
2104 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
2105 printf(_("The entire disk partition should start "
Eric Andersen040f4402003-07-30 08:40:37 +00002106 "at block 0,\n"
2107 "not at diskblock %d.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00002108 sgi_get_start_sector(Index[0]));
Eric Andersen040f4402003-07-30 08:40:37 +00002109 if (debug) /* I do not understand how some disks fulfil it */
Rob Landleyb73451d2006-02-24 16:29:00 +00002110 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
2111 printf(_("The entire disk partition is only %d diskblock large,\n"
2112 "but the disk is %d diskblocks long.\n"),
2113 sgi_get_num_sectors(Index[0]), lastblock);
Eric Andersen040f4402003-07-30 08:40:37 +00002114 lastblock = sgi_get_num_sectors(Index[0]);
Eric Andersen040f4402003-07-30 08:40:37 +00002115 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002116 if (verbose)
2117 printf(_("One Partition (#11) should cover the entire disk.\n"));
2118 if (debug > 2)
2119 printf("sysid=%d\tpartition=%d\n",
2120 sgi_get_sysid(Index[0]), Index[0]+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002121 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002122 for (i = 1, start = 0; i < sortcount; i++) {
2123 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
2124
2125 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
2126 if (debug) /* I do not understand how some disks fulfil it */
2127 if (verbose)
2128 printf(_("Partition %d does not start on cylinder boundary.\n"),
2129 Index[i]+1);
2130 }
2131 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
2132 if (debug) /* I do not understand how some disks fulfil it */
2133 if (verbose)
2134 printf(_("Partition %d does not end on cylinder boundary.\n"),
2135 Index[i]+1);
2136 }
2137 /* We cannot handle several "entire disk" entries. */
2138 if (sgi_get_sysid(Index[i]) == ENTIRE_DISK) continue;
2139 if (start > sgi_get_start_sector(Index[i])) {
2140 if (verbose)
2141 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
2142 Index[i-1]+1, Index[i]+1,
2143 start - sgi_get_start_sector(Index[i]));
2144 if (gap > 0) gap = -gap;
2145 if (gap == 0) gap = -1;
2146 }
2147 if (start < sgi_get_start_sector(Index[i])) {
2148 if (verbose)
2149 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2150 sgi_get_start_sector(Index[i]) - start,
2151 start, sgi_get_start_sector(Index[i])-1);
2152 gap += sgi_get_start_sector(Index[i]) - start;
2153 add2freelist(start, sgi_get_start_sector(Index[i]));
2154 }
2155 start = sgi_get_start_sector(Index[i])
2156 + sgi_get_num_sectors(Index[i]);
2157 if (debug > 1) {
2158 if (verbose)
2159 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
2160 sgi_get_start_sector(Index[i]),
2161 sgi_get_num_sectors(Index[i]),
2162 sgi_get_sysid(Index[i]));
2163 }
2164 }
2165 if (start < lastblock) {
2166 if (verbose)
2167 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
2168 lastblock - start, start, lastblock-1);
2169 gap += lastblock - start;
2170 add2freelist(start, lastblock);
2171 }
2172 /*
2173 * Done with arithmetics
2174 * Go for details now
2175 */
2176 if (verbose) {
2177 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
2178 printf(_("\nThe boot partition does not exist.\n"));
2179 }
2180 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
2181 printf(_("\nThe swap partition does not exist.\n"));
2182 } else {
2183 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
2184 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
2185 printf(_("\nThe swap partition has no swap type.\n"));
2186 }
2187 if (sgi_check_bootfile("/unix"))
2188 printf(_("\tYou have chosen an unusual boot file name.\n"));
2189 }
2190 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002191}
2192
2193static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002194sgi_gaps(void)
2195{
2196 /*
2197 * returned value is:
2198 * = 0 : disk is properly filled to the rim
2199 * < 0 : there is an overlap
2200 * > 0 : there is still some vacant space
2201 */
2202 return verify_sgi(0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002203}
2204
2205static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002206sgi_change_sysid(int i, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002207{
Rob Landleyb73451d2006-02-24 16:29:00 +00002208 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
2209 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
2210 return;
2211 }
2212 if (((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
2213 && (sgi_get_start_sector(i) < 1) ) {
2214 read_chars(
2215 _("It is highly recommended that the partition at offset 0\n"
2216 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
2217 "retrieve from its directory standalone tools like sash and fx.\n"
2218 "Only the \"SGI volume\" entire disk section may violate this.\n"
2219 "Type YES if you are sure about tagging this partition differently.\n"));
2220 if (strcmp(line_ptr, _("YES\n")))
2221 return;
2222 }
2223 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002224}
2225
2226/* returns partition index of first entry marked as entire disk */
2227static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002228sgi_entire(void)
2229{
2230 int i;
Eric Andersen040f4402003-07-30 08:40:37 +00002231
Rob Landleyb73451d2006-02-24 16:29:00 +00002232 for (i = 0; i < 16; i++)
2233 if (sgi_get_sysid(i) == SGI_VOLUME)
2234 return i;
2235 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002236}
2237
2238static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002239sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
2240{
2241 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
2242 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
2243 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
2244 set_changed(i);
2245 if (sgi_gaps() < 0) /* rebuild freelist */
2246 printf(_("Do You know, You got a partition overlap on the disk?\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002247}
2248
2249static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002250sgi_set_entire(void)
2251{
2252 int n;
Eric Andersen040f4402003-07-30 08:40:37 +00002253
Rob Landleyb73451d2006-02-24 16:29:00 +00002254 for (n = 10; n < partitions; n++) {
2255 if(!sgi_get_num_sectors(n) ) {
2256 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
2257 break;
2258 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002259 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002260}
2261
2262static void
2263sgi_set_volhdr(void)
2264{
Rob Landleyb73451d2006-02-24 16:29:00 +00002265 int n;
2266
2267 for (n = 8; n < partitions; n++) {
2268 if (!sgi_get_num_sectors(n)) {
2269 /*
2270 * 5 cylinders is an arbitrary value I like
2271 * IRIX 5.3 stored files in the volume header
2272 * (like sash, symmon, fx, ide) with ca. 3200
2273 * sectors.
2274 */
2275 if (heads * sectors * 5 < sgi_get_lastblock())
2276 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
2277 break;
2278 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002279 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002280}
2281
2282static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002283sgi_delete_partition(int i)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002284{
Rob Landleyb73451d2006-02-24 16:29:00 +00002285 sgi_set_partition(i, 0, 0, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002286}
2287
2288static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002289sgi_add_partition(int n, int sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002290{
Rob Landleyb73451d2006-02-24 16:29:00 +00002291 char mesg[256];
2292 unsigned int first = 0, last = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002293
Rob Landleyb73451d2006-02-24 16:29:00 +00002294 if (n == 10) {
2295 sys = SGI_VOLUME;
2296 } else if (n == 8) {
2297 sys = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002298 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002299 if(sgi_get_num_sectors(n)) {
2300 printf(_("Partition %d is already defined. Delete "
2301 "it before re-adding it.\n"), n + 1);
2302 return;
2303 }
2304 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
2305 printf(_("Attempting to generate entire disk entry automatically.\n"));
2306 sgi_set_entire();
2307 sgi_set_volhdr();
2308 }
2309 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
2310 printf(_("The entire disk is already covered with partitions.\n"));
2311 return;
2312 }
2313 if (sgi_gaps() < 0) {
2314 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
2315 return;
2316 }
2317 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2318 while (1) {
2319 if(sys == SGI_VOLUME) {
2320 last = sgi_get_lastblock();
2321 first = read_int(0, 0, last-1, 0, mesg);
2322 if (first != 0) {
2323 printf(_("It is highly recommended that eleventh partition\n"
2324 "covers the entire disk and is of type `SGI volume'\n"));
2325 }
2326 } else {
2327 first = freelist[0].first;
2328 last = freelist[0].last;
2329 first = read_int(scround(first), scround(first), scround(last)-1,
2330 0, mesg);
2331 }
2332 if (display_in_cyl_units)
2333 first *= units_per_sector;
2334 else
2335 first = first; /* align to cylinder if you know how ... */
2336 if(!last )
2337 last = isinfreelist(first);
2338 if(last == 0) {
2339 printf(_("You will get a partition overlap on the disk. "
2340 "Fix it first!\n"));
2341 } else
2342 break;
2343 }
2344 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
2345 last = read_int(scround(first), scround(last)-1, scround(last)-1,
2346 scround(first), mesg)+1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002347 if (display_in_cyl_units)
Rob Landleyb73451d2006-02-24 16:29:00 +00002348 last *= units_per_sector;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002349 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002350 last = last; /* align to cylinder if You know how ... */
2351 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
2352 printf(_("It is highly recommended that eleventh partition\n"
2353 "covers the entire disk and is of type `SGI volume'\n"));
2354 sgi_set_partition(n, first, last-first, sys);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002355}
2356
Eric Andersen040f4402003-07-30 08:40:37 +00002357#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002358static void
2359create_sgilabel(void)
2360{
Rob Landleyb73451d2006-02-24 16:29:00 +00002361 struct hd_geometry geometry;
2362 struct {
2363 unsigned int start;
2364 unsigned int nsect;
2365 int sysid;
2366 } old[4];
2367 int i = 0;
2368 long longsectors; /* the number of sectors on the device */
2369 int res; /* the result from the ioctl */
2370 int sec_fac; /* the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002371
Rob Landleyb73451d2006-02-24 16:29:00 +00002372 sec_fac = sector_size / 512; /* determine the sector factor */
Eric Andersen040f4402003-07-30 08:40:37 +00002373
Rob Landleyb73451d2006-02-24 16:29:00 +00002374 fprintf( stderr,
2375 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
2376 "until you decide to write them. After that, of course, the previous\n"
2377 "content will be unrecoverably lost.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002378
Rob Landleyb73451d2006-02-24 16:29:00 +00002379 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
2380 res = ioctl(fd, BLKGETSIZE, &longsectors);
2381 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2382 heads = geometry.heads;
2383 sectors = geometry.sectors;
2384 if (res == 0) {
2385 /* the get device size ioctl was successful */
2386 cylinders = longsectors / (heads * sectors);
2387 cylinders /= sec_fac;
2388 } else {
2389 /* otherwise print error and use truncated version */
2390 cylinders = geometry.cylinders;
2391 fprintf(stderr,
2392 _("Warning: BLKGETSIZE ioctl failed on %s. "
2393 "Using geometry cylinder value of %d.\n"
2394 "This value may be truncated for devices"
2395 " > 33.8 GB.\n"), disk_device, cylinders);
2396 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002397 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002398 for (i = 0; i < 4; i++) {
2399 old[i].sysid = 0;
2400 if (valid_part_table_flag(MBRbuffer)) {
2401 if(get_part_table(i)->sys_ind) {
2402 old[i].sysid = get_part_table(i)->sys_ind;
2403 old[i].start = get_start_sect(get_part_table(i));
2404 old[i].nsect = get_nr_sects(get_part_table(i));
2405 printf(_("Trying to keep parameters of partition %d.\n"), i);
2406 if (debug)
2407 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
2408 old[i].sysid, old[i].start, old[i].nsect);
2409 }
2410 }
2411 }
Eric Andersen040f4402003-07-30 08:40:37 +00002412
Rob Landleyb73451d2006-02-24 16:29:00 +00002413 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2414 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
2415 sgilabel->boot_part = SGI_SSWAP16(0);
2416 sgilabel->swap_part = SGI_SSWAP16(1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002417
Rob Landleyb73451d2006-02-24 16:29:00 +00002418 /* sizeof(sgilabel->boot_file) = 16 > 6 */
2419 memset(sgilabel->boot_file, 0, 16);
2420 strcpy((char*)sgilabel->boot_file, "/unix");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002421
Rob Landleyb73451d2006-02-24 16:29:00 +00002422 sgilabel->devparam.skew = (0);
2423 sgilabel->devparam.gap1 = (0);
2424 sgilabel->devparam.gap2 = (0);
2425 sgilabel->devparam.sparecyl = (0);
2426 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
2427 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
2428 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002429 /* tracks/cylinder (heads) */
Rob Landleyb73451d2006-02-24 16:29:00 +00002430 sgilabel->devparam.cmd_tag_queue_depth = (0);
2431 sgilabel->devparam.unused0 = (0);
2432 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
2433 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002434 /* sectors/track */
Rob Landleyb73451d2006-02-24 16:29:00 +00002435 sgilabel->devparam.bytes = SGI_SSWAP16(512);
2436 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
2437 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002438 IGNORE_ERRORS|RESEEK);
Rob Landleyb73451d2006-02-24 16:29:00 +00002439 sgilabel->devparam.datarate = SGI_SSWAP32(0);
2440 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
2441 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
2442 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
2443 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
2444 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
2445 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
2446 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
2447 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
2448 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
2449 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
2450 sgi_label = 1;
2451 partitions = 16;
2452 sgi_volumes = 15;
2453 sgi_set_entire();
2454 sgi_set_volhdr();
2455 for (i = 0; i < 4; i++) {
2456 if(old[i].sysid) {
2457 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
2458 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002459 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002460}
2461
2462static void
2463sgi_set_xcyl(void)
2464{
Rob Landleyb73451d2006-02-24 16:29:00 +00002465 /* do nothing in the beginning */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002466}
Eric Andersen040f4402003-07-30 08:40:37 +00002467#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002468
2469/* _____________________________________________________________
2470 */
2471
Eric Andersen040f4402003-07-30 08:40:37 +00002472static sgiinfo *
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002473fill_sgiinfo(void)
2474{
Rob Landleyb73451d2006-02-24 16:29:00 +00002475 sgiinfo *info = calloc(1, sizeof(sgiinfo));
Eric Andersen040f4402003-07-30 08:40:37 +00002476
Rob Landleyb73451d2006-02-24 16:29:00 +00002477 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
2478 info->b1 = SGI_SSWAP32(-1);
2479 info->b2 = SGI_SSWAP16(-1);
2480 info->b3 = SGI_SSWAP16(1);
2481 /* You may want to replace this string !!!!!!! */
2482 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
2483 strcpy( (char*)info->serial, "0000" );
2484 info->check1816 = SGI_SSWAP16(18*256 +16 );
2485 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
2486 return info;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002487}
2488#endif /* SGI_LABEL */
2489
2490
2491#ifdef CONFIG_FEATURE_SUN_LABEL
2492/*
2493 * fdisksunlabel.c
2494 *
2495 * I think this is mostly, or entirely, due to
2496 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
2497 *
2498 * Merged with fdisk for other architectures, aeb, June 1998.
2499 *
2500 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
2501 * Internationalization
2502 */
2503
2504
Rob Landleyb73451d2006-02-24 16:29:00 +00002505static int sun_other_endian;
2506static int scsi_disk;
2507static int floppy;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002508
2509#ifndef IDE0_MAJOR
2510#define IDE0_MAJOR 3
2511#endif
2512#ifndef IDE1_MAJOR
2513#define IDE1_MAJOR 22
2514#endif
Eric Andersen040f4402003-07-30 08:40:37 +00002515
Rob Landleyb73451d2006-02-24 16:29:00 +00002516static void
2517guess_device_type(void)
2518{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002519 struct stat bootstat;
2520
Rob Landleyb73451d2006-02-24 16:29:00 +00002521 if (fstat(fd, &bootstat) < 0) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002522 scsi_disk = 0;
2523 floppy = 0;
2524 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002525 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
2526 major(bootstat.st_rdev) == IDE1_MAJOR)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002527 scsi_disk = 0;
2528 floppy = 0;
2529 } else if (S_ISBLK(bootstat.st_mode)
Rob Landleyb73451d2006-02-24 16:29:00 +00002530 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002531 scsi_disk = 0;
2532 floppy = 1;
2533 } else {
2534 scsi_disk = 1;
2535 floppy = 0;
2536 }
2537}
2538
2539static const struct systypes sun_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002540 { "\x00" "Empty" }, /* 0 */
2541 { "\x01" "Boot" }, /* 1 */
2542 { "\x02" "SunOS root" }, /* 2 */
2543 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
2544 { "\x04" "SunOS usr" }, /* 4 */
2545 { "\x05" "Whole disk" }, /* WHOLE_DISK */
2546 { "\x06" "SunOS stand" }, /* 6 */
2547 { "\x07" "SunOS var" }, /* 7 */
2548 { "\x08" "SunOS home" }, /* 8 */
2549 { "\x82" "Linux swap" }, /* LINUX_SWAP */
2550 { "\x83" "Linux native" }, /* LINUX_NATIVE */
2551 { "\x8e" "Linux LVM" }, /* 0x8e */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002552/* New (2.2.x) raid partition with autodetect using persistent superblock */
Rob Landleyb73451d2006-02-24 16:29:00 +00002553 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
2554 { NULL }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002555};
2556
2557
2558static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002559set_sun_partition(int i, uint start, uint stop, int sysid)
2560{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002561 sunlabel->infos[i].id = sysid;
2562 sunlabel->partitions[i].start_cylinder =
2563 SUN_SSWAP32(start / (heads * sectors));
2564 sunlabel->partitions[i].num_sectors =
2565 SUN_SSWAP32(stop - start);
2566 set_changed(i);
2567}
2568
2569static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002570sun_nolabel(void)
2571{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002572 sun_label = 0;
2573 sunlabel->magic = 0;
2574 partitions = 4;
2575}
2576
2577static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002578check_sun_label(void)
2579{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002580 unsigned short *ush;
2581 int csum;
2582
Rob Landleyb73451d2006-02-24 16:29:00 +00002583 if (sunlabel->magic != SUN_LABEL_MAGIC
2584 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002585 sun_label = 0;
2586 sun_other_endian = 0;
2587 return 0;
2588 }
2589 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
2590 ush = ((unsigned short *) (sunlabel + 1)) - 1;
2591 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
2592 if (csum) {
2593 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
2594 "Probably you'll have to set all the values,\n"
2595 "e.g. heads, sectors, cylinders and partitions\n"
2596 "or force a fresh label (s command in main menu)\n"));
2597 } else {
2598 heads = SUN_SSWAP16(sunlabel->ntrks);
2599 cylinders = SUN_SSWAP16(sunlabel->ncyl);
2600 sectors = SUN_SSWAP16(sunlabel->nsect);
2601 }
2602 update_units();
2603 sun_label = 1;
2604 partitions = 8;
2605 return 1;
2606}
2607
2608static const struct sun_predefined_drives {
2609 const char *vendor;
2610 const char *model;
2611 unsigned short sparecyl;
2612 unsigned short ncyl;
2613 unsigned short nacyl;
2614 unsigned short pcylcount;
2615 unsigned short ntrks;
2616 unsigned short nsect;
2617 unsigned short rspeed;
2618} sun_drives[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00002619 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
2620 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
2621 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
2622 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
2623 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
2624 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
2625 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
2626 { "","SUN0104",1,974,2,1019,6,35,3662},
2627 { "","SUN0207",4,1254,2,1272,9,36,3600},
2628 { "","SUN0327",3,1545,2,1549,9,46,3600},
2629 { "","SUN0340",0,1538,2,1544,6,72,4200},
2630 { "","SUN0424",2,1151,2,2500,9,80,4400},
2631 { "","SUN0535",0,1866,2,2500,7,80,5400},
2632 { "","SUN0669",5,1614,2,1632,15,54,3600},
2633 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
2634 { "","SUN1.05",0,2036,2,2038,14,72,5400},
2635 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
2636 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
2637 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002638};
2639
2640static const struct sun_predefined_drives *
Rob Landleyb73451d2006-02-24 16:29:00 +00002641sun_autoconfigure_scsi(void)
2642{
2643 const struct sun_predefined_drives *p = NULL;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002644
2645#ifdef SCSI_IOCTL_GET_IDLUN
Rob Landleyb73451d2006-02-24 16:29:00 +00002646 unsigned int id[2];
2647 char buffer[2048];
2648 char buffer2[2048];
2649 FILE *pfd;
2650 char *vendor;
2651 char *model;
2652 char *q;
2653 int i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002654
Rob Landleyb73451d2006-02-24 16:29:00 +00002655 if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
2656 sprintf(buffer,
2657 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002658#if 0
Rob Landleyb73451d2006-02-24 16:29:00 +00002659 ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002660#else
Rob Landleyb73451d2006-02-24 16:29:00 +00002661 /* This is very wrong (works only if you have one HBA),
2662 but I haven't found a way how to get hostno
2663 from the current kernel */
2664 0,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002665#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002666 (id[0]>>16) & 0xff,
2667 id[0] & 0xff,
2668 (id[0]>>8) & 0xff
2669 );
2670 pfd = fopen("/proc/scsi/scsi","r");
2671 if (pfd) {
2672 while (fgets(buffer2, 2048, pfd)) {
2673 if (!strcmp(buffer, buffer2)) {
2674 if (fgets(buffer2,2048,pfd)) {
2675 q = strstr(buffer2,"Vendor: ");
2676 if (q) {
2677 q += 8;
2678 vendor = q;
2679 q = strstr(q," ");
2680 *q++ = 0; /* truncate vendor name */
2681 q = strstr(q,"Model: ");
2682 if (q) {
2683 *q = 0;
2684 q += 7;
2685 model = q;
2686 q = strstr(q," Rev: ");
2687 if (q) {
2688 *q = 0;
2689 for (i = 0; i < SIZE(sun_drives); i++) {
2690 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
2691 continue;
2692 if (!strstr(model, sun_drives[i].model))
2693 continue;
2694 printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
2695 p = sun_drives + i;
2696 break;
2697 }
2698 }
2699 }
2700 }
2701 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002702 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002703 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002704 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002705 fclose(pfd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002706 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002707 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002708#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00002709 return p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002710}
2711
Rob Landleyb73451d2006-02-24 16:29:00 +00002712static void
2713create_sunlabel(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002714{
2715 struct hd_geometry geometry;
2716 unsigned int ndiv;
2717 int i;
2718 unsigned char c;
2719 const struct sun_predefined_drives *p = NULL;
2720
2721 fprintf(stderr,
Rob Landleyb73451d2006-02-24 16:29:00 +00002722 _("Building a new sun disklabel. Changes will remain in memory only,\n"
2723 "until you decide to write them. After that, of course, the previous\n"
2724 "content won't be recoverable.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002725#if BYTE_ORDER == LITTLE_ENDIAN
2726 sun_other_endian = 1;
2727#else
2728 sun_other_endian = 0;
2729#endif
2730 memset(MBRbuffer, 0, sizeof(MBRbuffer));
2731 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
2732 if (!floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002733 puts(_("Drive type\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002734 " ? auto configure\n"
2735 " 0 custom (with hardware detected defaults)"));
Rob Landleyb73451d2006-02-24 16:29:00 +00002736 for (i = 0; i < SIZE(sun_drives); i++) {
2737 printf(" %c %s%s%s\n",
2738 i + 'a', sun_drives[i].vendor,
2739 (*sun_drives[i].vendor) ? " " : "",
2740 sun_drives[i].model);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002741 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002742 while (1) {
2743 c = read_char(_("Select type (? for auto, 0 for custom): "));
2744 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
2745 p = sun_drives + c - 'a';
2746 break;
2747 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
2748 p = sun_drives + c - 'A';
2749 break;
2750 } else if (c == '0') {
2751 break;
2752 } else if (c == '?' && scsi_disk) {
2753 p = sun_autoconfigure_scsi();
2754 if (!p)
2755 printf(_("Autoconfigure failed.\n"));
2756 else
2757 break;
2758 }
2759 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002760 }
2761 if (!p || floppy) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002762 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
2763 heads = geometry.heads;
2764 sectors = geometry.sectors;
2765 cylinders = geometry.cylinders;
2766 } else {
2767 heads = 0;
2768 sectors = 0;
2769 cylinders = 0;
2770 }
2771 if (floppy) {
2772 sunlabel->nacyl = 0;
2773 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
2774 sunlabel->rspeed = SUN_SSWAP16(300);
2775 sunlabel->ilfact = SUN_SSWAP16(1);
2776 sunlabel->sparecyl = 0;
2777 } else {
2778 heads = read_int(1,heads,1024,0,_("Heads"));
2779 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002780 if (cylinders)
Rob Landleyb73451d2006-02-24 16:29:00 +00002781 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002782 else
Rob Landleyb73451d2006-02-24 16:29:00 +00002783 cylinders = read_int(1,0,65535,0,_("Cylinders"));
2784 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
2785 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
2786 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
2787 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
2788 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
2789 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002790 } else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002791 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
2792 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
2793 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
2794 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
2795 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
2796 sunlabel->nsect = SUN_SSWAP16(p->nsect);
2797 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
2798 sunlabel->ilfact = SUN_SSWAP16(1);
2799 cylinders = p->ncyl;
2800 heads = p->ntrks;
2801 sectors = p->nsect;
2802 puts(_("You may change all the disk params from the x menu"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002803 }
2804
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00002805 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
Rob Landleyb73451d2006-02-24 16:29:00 +00002806 "%s%s%s cyl %d alt %d hd %d sec %d",
2807 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
2808 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002809 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
2810
2811 sunlabel->ntrks = SUN_SSWAP16(heads);
2812 sunlabel->nsect = SUN_SSWAP16(sectors);
2813 sunlabel->ncyl = SUN_SSWAP16(cylinders);
2814 if (floppy)
Rob Landleyb73451d2006-02-24 16:29:00 +00002815 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002816 else {
Rob Landleyb73451d2006-02-24 16:29:00 +00002817 if (cylinders * heads * sectors >= 150 * 2048) {
2818 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
2819 } else
2820 ndiv = cylinders * 2 / 3;
2821 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
2822 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
2823 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002824 }
2825 set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
2826 {
2827 unsigned short *ush = (unsigned short *)sunlabel;
2828 unsigned short csum = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00002829 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002830 csum ^= *ush++;
2831 sunlabel->csum = csum;
2832 }
2833
2834 set_all_unchanged();
2835 set_changed(0);
2836 get_boot(create_empty_sun);
2837}
2838
2839static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002840toggle_sunflags(int i, unsigned char mask)
2841{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002842 if (sunlabel->infos[i].flags & mask)
2843 sunlabel->infos[i].flags &= ~mask;
Rob Landleyb73451d2006-02-24 16:29:00 +00002844 else
2845 sunlabel->infos[i].flags |= mask;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002846 set_changed(i);
2847}
2848
2849static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002850fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
2851{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002852 int i, continuous = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00002853
2854 *start = 0;
2855 *stop = cylinders * heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002856 for (i = 0; i < partitions; i++) {
2857 if (sunlabel->partitions[i].num_sectors
Rob Landleyb73451d2006-02-24 16:29:00 +00002858 && sunlabel->infos[i].id
2859 && sunlabel->infos[i].id != WHOLE_DISK) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002860 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
2861 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
2862 if (continuous) {
2863 if (starts[i] == *start)
2864 *start += lens[i];
2865 else if (starts[i] + lens[i] >= *stop)
2866 *stop = starts[i];
2867 else
2868 continuous = 0;
2869 /* There will be probably more gaps
2870 than one, so lets check afterwards */
2871 }
2872 } else {
2873 starts[i] = 0;
2874 lens[i] = 0;
2875 }
2876 }
2877}
2878
2879static uint *verify_sun_starts;
2880
2881static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002882verify_sun_cmp(int *a, int *b)
2883{
2884 if (*a == -1) return 1;
2885 if (*b == -1) return -1;
2886 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
2887 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002888}
2889
2890static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002891verify_sun(void)
2892{
2893 uint starts[8], lens[8], start, stop;
2894 int i,j,k,starto,endo;
2895 int array[8];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002896
Rob Landleyb73451d2006-02-24 16:29:00 +00002897 verify_sun_starts = starts;
2898 fetch_sun(starts,lens,&start,&stop);
2899 for (k = 0; k < 7; k++) {
2900 for (i = 0; i < 8; i++) {
2901 if (k && (lens[i] % (heads * sectors))) {
2902 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002903 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002904 if (lens[i]) {
2905 for (j = 0; j < i; j++)
2906 if (lens[j]) {
2907 if (starts[j] == starts[i]+lens[i]) {
2908 starts[j] = starts[i]; lens[j] += lens[i];
2909 lens[i] = 0;
2910 } else if (starts[i] == starts[j]+lens[j]){
2911 lens[j] += lens[i];
2912 lens[i] = 0;
2913 } else if (!k) {
2914 if (starts[i] < starts[j]+lens[j]
2915 && starts[j] < starts[i]+lens[i]) {
2916 starto = starts[i];
2917 if (starts[j] > starto)
2918 starto = starts[j];
2919 endo = starts[i]+lens[i];
2920 if (starts[j]+lens[j] < endo)
2921 endo = starts[j]+lens[j];
2922 printf(_("Partition %d overlaps with others in "
2923 "sectors %d-%d\n"), i+1, starto, endo);
2924 }
2925 }
2926 }
2927 }
2928 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002929 }
Rob Landleyb73451d2006-02-24 16:29:00 +00002930 for (i = 0; i < 8; i++) {
2931 if (lens[i])
2932 array[i] = i;
2933 else
2934 array[i] = -1;
2935 }
2936 qsort(array,SIZE(array),sizeof(array[0]),
2937 (int (*)(const void *,const void *)) verify_sun_cmp);
2938 if (array[0] == -1) {
2939 printf(_("No partitions defined\n"));
2940 return;
2941 }
2942 stop = cylinders * heads * sectors;
2943 if (starts[array[0]])
2944 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
2945 for (i = 0; i < 7 && array[i+1] != -1; i++) {
2946 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
2947 }
2948 start = starts[array[i]] + lens[array[i]];
2949 if (start < stop)
2950 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002951}
2952
2953static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002954add_sun_partition(int n, int sys)
2955{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002956 uint start, stop, stop2;
2957 uint starts[8], lens[8];
2958 int whole_disk = 0;
2959
2960 char mesg[256];
2961 int i, first, last;
2962
2963 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
2964 printf(_("Partition %d is already defined. Delete "
2965 "it before re-adding it.\n"), n + 1);
2966 return;
2967 }
2968
2969 fetch_sun(starts,lens,&start,&stop);
2970 if (stop <= start) {
2971 if (n == 2)
2972 whole_disk = 1;
2973 else {
2974 printf(_("Other partitions already cover the whole disk.\nDelete "
Rob Landleyb73451d2006-02-24 16:29:00 +00002975 "some/shrink them before retry.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002976 return;
2977 }
2978 }
2979 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
Rob Landleyb73451d2006-02-24 16:29:00 +00002980 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002981 if (whole_disk)
2982 first = read_int(0, 0, 0, 0, mesg);
2983 else
2984 first = read_int(scround(start), scround(stop)+1,
2985 scround(stop), 0, mesg);
2986 if (display_in_cyl_units)
2987 first *= units_per_sector;
2988 else
2989 /* Starting sector has to be properly aligned */
2990 first = (first + heads * sectors - 1) / (heads * sectors);
2991 if (n == 2 && first != 0)
Rob Landleyb73451d2006-02-24 16:29:00 +00002992 printf("\
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002993It is highly recommended that the third partition covers the whole disk\n\
2994and is of type `Whole disk'\n");
2995 /* ewt asks to add: "don't start a partition at cyl 0"
2996 However, edmundo@rano.demon.co.uk writes:
2997 "In addition to having a Sun partition table, to be able to
2998 boot from the disc, the first partition, /dev/sdX1, must
2999 start at cylinder 0. This means that /dev/sdX1 contains
3000 the partition table and the boot block, as these are the
3001 first two sectors of the disc. Therefore you must be
3002 careful what you use /dev/sdX1 for. In particular, you must
3003 not use a partition starting at cylinder 0 for Linux swap,
3004 as that would overwrite the partition table and the boot
3005 block. You may, however, use such a partition for a UFS
3006 or EXT2 file system, as these file systems leave the first
3007 1024 bytes undisturbed. */
3008 /* On the other hand, one should not use partitions
3009 starting at block 0 in an md, or the label will
3010 be trashed. */
3011 for (i = 0; i < partitions; i++)
Rob Landleyb73451d2006-02-24 16:29:00 +00003012 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003013 break;
3014 if (i < partitions && !whole_disk) {
3015 if (n == 2 && !first) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003016 whole_disk = 1;
3017 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003018 }
3019 printf(_("Sector %d is already allocated\n"), first);
3020 } else
3021 break;
3022 }
3023 stop = cylinders * heads * sectors;
3024 stop2 = stop;
3025 for (i = 0; i < partitions; i++) {
3026 if (starts[i] > first && starts[i] < stop)
3027 stop = starts[i];
3028 }
3029 snprintf(mesg, sizeof(mesg),
Rob Landleyb73451d2006-02-24 16:29:00 +00003030 _("Last %s or +size or +sizeM or +sizeK"),
3031 str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003032 if (whole_disk)
3033 last = read_int(scround(stop2), scround(stop2), scround(stop2),
3034 0, mesg);
3035 else if (n == 2 && !first)
3036 last = read_int(scround(first), scround(stop2), scround(stop2),
3037 scround(first), mesg);
3038 else
3039 last = read_int(scround(first), scround(stop), scround(stop),
3040 scround(first), mesg);
3041 if (display_in_cyl_units)
3042 last *= units_per_sector;
3043 if (n == 2 && !first) {
3044 if (last >= stop2) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003045 whole_disk = 1;
3046 last = stop2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003047 } else if (last > stop) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003048 printf(_("You haven't covered the whole disk with "
3049 "the 3rd partition, but your value\n"
3050 "%d %s covers some other partition. "
3051 "Your entry has been changed\n"
3052 "to %d %s\n"),
3053 scround(last), str_units(SINGULAR),
3054 scround(stop), str_units(SINGULAR));
3055 last = stop;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003056 }
3057 } else if (!whole_disk && last > stop)
3058 last = stop;
3059
Rob Landleyb73451d2006-02-24 16:29:00 +00003060 if (whole_disk)
3061 sys = WHOLE_DISK;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003062 set_sun_partition(n, first, last, sys);
3063}
3064
3065static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003066sun_delete_partition(int i)
3067{
Eric Andersen040f4402003-07-30 08:40:37 +00003068 unsigned int nsec;
3069
Rob Landleyb73451d2006-02-24 16:29:00 +00003070 if (i == 2
3071 && sunlabel->infos[i].id == WHOLE_DISK
3072 && !sunlabel->partitions[i].start_cylinder
3073 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003074 printf(_("If you want to maintain SunOS/Solaris compatibility, "
Rob Landleyb73451d2006-02-24 16:29:00 +00003075 "consider leaving this\n"
3076 "partition as Whole disk (5), starting at 0, with %u "
3077 "sectors\n"), nsec);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003078 sunlabel->infos[i].id = 0;
3079 sunlabel->partitions[i].num_sectors = 0;
3080}
3081
3082static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003083sun_change_sysid(int i, int sys)
3084{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003085 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003086 read_chars(
3087 _("It is highly recommended that the partition at offset 0\n"
3088 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
3089 "there may destroy your partition table and bootblock.\n"
3090 "Type YES if you're very sure you would like that partition\n"
3091 "tagged with 82 (Linux swap): "));
3092 if (strcmp (line_ptr, _("YES\n")))
3093 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003094 }
3095 switch (sys) {
3096 case SUNOS_SWAP:
3097 case LINUX_SWAP:
3098 /* swaps are not mountable by default */
3099 sunlabel->infos[i].flags |= 0x01;
3100 break;
3101 default:
3102 /* assume other types are mountable;
3103 user can change it anyway */
3104 sunlabel->infos[i].flags &= ~0x01;
3105 break;
3106 }
3107 sunlabel->infos[i].id = sys;
3108}
3109
3110static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003111sun_list_table(int xtra)
3112{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003113 int i, w;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003114
3115 w = strlen(disk_device);
3116 if (xtra)
3117 printf(
3118 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
3119 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
3120 "%d extra sects/cyl, interleave %d:1\n"
3121 "%s\n"
3122 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003123 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
3124 cylinders, SUN_SSWAP16(sunlabel->nacyl),
3125 SUN_SSWAP16(sunlabel->pcylcount),
3126 SUN_SSWAP16(sunlabel->sparecyl),
3127 SUN_SSWAP16(sunlabel->ilfact),
3128 (char *)sunlabel,
3129 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003130 else
3131 printf(
3132 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
3133 "Units = %s of %d * 512 bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003134 disk_device, heads, sectors, cylinders,
3135 str_units(PLURAL), units_per_sector);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003136
3137 printf(_("%*s Flag Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003138 w + 1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003139 for (i = 0 ; i < partitions; i++) {
3140 if (sunlabel->partitions[i].num_sectors) {
Eric Andersenacd244a2002-12-11 03:49:33 +00003141 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
3142 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
Rob Landleyb73451d2006-02-24 16:29:00 +00003143 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
3144 partname(disk_device, i+1, w), /* device */
3145 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
3146 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
3147 (long) scround(start), /* start */
3148 (long) scround(start+len), /* end */
3149 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
3150 sunlabel->infos[i].id, /* type id */
3151 partition_type(sunlabel->infos[i].id)); /* type name */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003152 }
3153 }
3154}
3155
Eric Andersen040f4402003-07-30 08:40:37 +00003156#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3157
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003158static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003159sun_set_alt_cyl(void)
3160{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003161 sunlabel->nacyl =
3162 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003163 _("Number of alternate cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003164}
3165
3166static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003167sun_set_ncyl(int cyl)
3168{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003169 sunlabel->ncyl = SUN_SSWAP16(cyl);
3170}
3171
3172static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003173sun_set_xcyl(void)
3174{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003175 sunlabel->sparecyl =
3176 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003177 _("Extra sectors per cylinder")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003178}
3179
3180static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003181sun_set_ilfact(void)
3182{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003183 sunlabel->ilfact =
3184 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003185 _("Interleave factor")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003186}
3187
3188static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003189sun_set_rspeed(void)
3190{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003191 sunlabel->rspeed =
3192 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003193 _("Rotation speed (rpm)")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003194}
3195
3196static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003197sun_set_pcylcount(void)
3198{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003199 sunlabel->pcylcount =
3200 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00003201 _("Number of physical cylinders")));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003202}
Eric Andersen040f4402003-07-30 08:40:37 +00003203#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003204
3205static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003206sun_write_table(void)
3207{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003208 unsigned short *ush = (unsigned short *)sunlabel;
3209 unsigned short csum = 0;
3210
Rob Landleyb73451d2006-02-24 16:29:00 +00003211 while (ush < (unsigned short *)(&sunlabel->csum))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003212 csum ^= *ush++;
3213 sunlabel->csum = csum;
3214 if (lseek(fd, 0, SEEK_SET) < 0)
3215 fdisk_fatal(unable_to_seek);
3216 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
3217 fdisk_fatal(unable_to_write);
3218}
3219#endif /* SUN_LABEL */
3220
3221/* DOS partition types */
3222
3223static const struct systypes i386_sys_types[] = {
Rob Landleyb73451d2006-02-24 16:29:00 +00003224 { "\x00" "Empty" },
3225 { "\x01" "FAT12" },
3226 { "\x04" "FAT16 <32M" },
3227 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
3228 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
3229 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
3230 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
3231 { "\x0b" "Win95 FAT32" },
3232 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is `Extended Int 13h' */
3233 { "\x0e" "Win95 FAT16 (LBA)" },
3234 { "\x0f" "Win95 Ext'd (LBA)" },
3235 { "\x11" "Hidden FAT12" },
3236 { "\x12" "Compaq diagnostics" },
3237 { "\x14" "Hidden FAT16 <32M" },
3238 { "\x16" "Hidden FAT16" },
3239 { "\x17" "Hidden HPFS/NTFS" },
3240 { "\x1b" "Hidden Win95 FAT32" },
3241 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
3242 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
3243 { "\x3c" "PartitionMagic recovery" },
3244 { "\x41" "PPC PReP Boot" },
3245 { "\x42" "SFS" },
3246 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
3247 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
3248 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
3249 { "\x82" "Linux swap" }, /* also Solaris */
3250 { "\x83" "Linux" },
3251 { "\x84" "OS/2 hidden C: drive" },
3252 { "\x85" "Linux extended" },
3253 { "\x86" "NTFS volume set" },
3254 { "\x87" "NTFS volume set" },
3255 { "\x8e" "Linux LVM" },
3256 { "\x9f" "BSD/OS" }, /* BSDI */
3257 { "\xa0" "IBM Thinkpad hibernation" },
3258 { "\xa5" "FreeBSD" }, /* various BSD flavours */
3259 { "\xa6" "OpenBSD" },
3260 { "\xa8" "Darwin UFS" },
3261 { "\xa9" "NetBSD" },
3262 { "\xab" "Darwin boot" },
3263 { "\xb7" "BSDI fs" },
3264 { "\xb8" "BSDI swap" },
3265 { "\xbe" "Solaris boot" },
3266 { "\xeb" "BeOS fs" },
3267 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
3268 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
3269 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
3270 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
3271 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
3272 autodetect using persistent
3273 superblock */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003274#ifdef CONFIG_WEIRD_PARTITION_TYPES
Rob Landleyb73451d2006-02-24 16:29:00 +00003275 { "\x02" "XENIX root" },
3276 { "\x03" "XENIX usr" },
3277 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
3278 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
3279 { "\x10" "OPUS" },
3280 { "\x18" "AST SmartSleep" },
3281 { "\x24" "NEC DOS" },
3282 { "\x39" "Plan 9" },
3283 { "\x40" "Venix 80286" },
3284 { "\x4d" "QNX4.x" },
3285 { "\x4e" "QNX4.x 2nd part" },
3286 { "\x4f" "QNX4.x 3rd part" },
3287 { "\x50" "OnTrack DM" },
3288 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
3289 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
3290 { "\x53" "OnTrack DM6 Aux3" },
3291 { "\x54" "OnTrackDM6" },
3292 { "\x55" "EZ-Drive" },
3293 { "\x56" "Golden Bow" },
3294 { "\x5c" "Priam Edisk" },
3295 { "\x61" "SpeedStor" },
3296 { "\x64" "Novell Netware 286" },
3297 { "\x65" "Novell Netware 386" },
3298 { "\x70" "DiskSecure Multi-Boot" },
3299 { "\x75" "PC/IX" },
3300 { "\x93" "Amoeba" },
3301 { "\x94" "Amoeba BBT" }, /* (bad block table) */
3302 { "\xa7" "NeXTSTEP" },
3303 { "\xbb" "Boot Wizard hidden" },
3304 { "\xc1" "DRDOS/sec (FAT-12)" },
3305 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
3306 { "\xc6" "DRDOS/sec (FAT-16)" },
3307 { "\xc7" "Syrinx" },
3308 { "\xda" "Non-FS data" },
3309 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003310 Concurrent DOS or CTOS */
Rob Landleyb73451d2006-02-24 16:29:00 +00003311 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
3312 { "\xdf" "BootIt" }, /* BootIt EMBRM */
3313 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003314 extended partition */
Rob Landleyb73451d2006-02-24 16:29:00 +00003315 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
3316 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003317 partition < 1024 cyl. */
Rob Landleyb73451d2006-02-24 16:29:00 +00003318 { "\xf1" "SpeedStor" },
3319 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
3320 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
3321 { "\xff" "BBT" }, /* Xenix Bad Block Table */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003322#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003323 { 0 }
3324};
3325
3326
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003327
3328/* A valid partition table sector ends in 0x55 0xaa */
3329static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003330part_table_flag(const char *b)
3331{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003332 return ((uint) b[510]) + (((uint) b[511]) << 8);
3333}
3334
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003335
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003336#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003337static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003338write_part_table_flag(char *b)
3339{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003340 b[510] = 0x55;
3341 b[511] = 0xaa;
3342}
3343
3344/* start_sect and nr_sects are stored little endian on all machines */
3345/* moreover, they are not aligned correctly */
3346static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003347store4_little_endian(unsigned char *cp, unsigned int val)
3348{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003349 cp[0] = (val & 0xff);
3350 cp[1] = ((val >> 8) & 0xff);
3351 cp[2] = ((val >> 16) & 0xff);
3352 cp[3] = ((val >> 24) & 0xff);
3353}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003354#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003355
3356static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003357read4_little_endian(const unsigned char *cp)
3358{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003359 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
3360 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
3361}
3362
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003363#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003364static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003365set_start_sect(struct partition *p, unsigned int start_sect)
3366{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003367 store4_little_endian(p->start4, start_sect);
3368}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003369#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003370
Eric Andersend9261492004-06-28 23:50:31 +00003371static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003372get_start_sect(const struct partition *p)
3373{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003374 return read4_little_endian(p->start4);
3375}
3376
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003377#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003378static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003379set_nr_sects(struct partition *p, int32_t nr_sects)
3380{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003381 store4_little_endian(p->size4, nr_sects);
3382}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003383#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003384
Eric Andersend9261492004-06-28 23:50:31 +00003385static int32_t
Rob Landleyb73451d2006-02-24 16:29:00 +00003386get_nr_sects(const struct partition *p)
3387{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003388 return read4_little_endian(p->size4);
3389}
3390
3391/* normally O_RDWR, -l option gives O_RDONLY */
3392static int type_open = O_RDWR;
3393
3394
Rob Landleyb73451d2006-02-24 16:29:00 +00003395static int ext_index; /* the prime extended partition */
3396static int listing; /* no aborts for fdisk -l */
3397static int dos_compatible_flag = ~0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003398#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3399static int dos_changed;
3400static int nowarn; /* no warnings for fdisk -l/-s */
3401#endif
3402
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003403
3404
Rob Landleyb73451d2006-02-24 16:29:00 +00003405static uint user_cylinders, user_heads, user_sectors;
3406static uint pt_heads, pt_sectors;
3407static uint kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003408
Eric Andersend9261492004-06-28 23:50:31 +00003409static off_t extended_offset; /* offset of link pointers */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003410
Eric Andersen040f4402003-07-30 08:40:37 +00003411static unsigned long long total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003412
3413
3414static jmp_buf listingbuf;
3415
Rob Landleyb73451d2006-02-24 16:29:00 +00003416static void fdisk_fatal(enum failure why)
3417{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003418 const char *message;
3419
3420 if (listing) {
3421 close(fd);
3422 longjmp(listingbuf, 1);
3423 }
3424
3425 switch (why) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003426 case unable_to_open:
3427 message = "Unable to open %s\n";
3428 break;
3429 case unable_to_read:
3430 message = "Unable to read %s\n";
3431 break;
3432 case unable_to_seek:
3433 message = "Unable to seek on %s\n";
3434 break;
3435 case unable_to_write:
3436 message = "Unable to write %s\n";
3437 break;
3438 case ioctl_error:
3439 message = "BLKGETSIZE ioctl failed on %s\n";
3440 break;
3441 default:
3442 message = "Fatal error\n";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003443 }
3444
3445 fputc('\n', stderr);
3446 fprintf(stderr, message, disk_device);
3447 exit(1);
3448}
3449
3450static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003451seek_sector(off_t secno)
3452{
Eric Andersen0a92f352004-03-30 09:21:54 +00003453 off_t offset = secno * sector_size;
3454 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003455 fdisk_fatal(unable_to_seek);
3456}
3457
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003458#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003459static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003460write_sector(off_t secno, char *buf)
3461{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003462 seek_sector(secno);
3463 if (write(fd, buf, sector_size) != sector_size)
3464 fdisk_fatal(unable_to_write);
3465}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003466#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003467
3468/* Allocate a buffer and read a partition table sector */
3469static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003470read_pte(struct pte *pe, off_t offset)
3471{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003472 pe->offset = offset;
3473 pe->sectorbuffer = (char *) xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003474 seek_sector(offset);
3475 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
3476 fdisk_fatal(unable_to_read);
3477#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003478 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003479#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003480 pe->part_table = pe->ext_pointer = NULL;
3481}
3482
3483static unsigned int
Rob Landleyb73451d2006-02-24 16:29:00 +00003484get_partition_start(const struct pte *pe)
3485{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003486 return pe->offset + get_start_sect(pe->part_table);
3487}
3488
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003489#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003490/*
3491 * Avoid warning about DOS partitions when no DOS partition was changed.
3492 * Here a heuristic "is probably dos partition".
3493 * We might also do the opposite and warn in all cases except
3494 * for "is probably nondos partition".
3495 */
3496static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003497is_dos_partition(int t)
3498{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003499 return (t == 1 || t == 4 || t == 6 ||
3500 t == 0x0b || t == 0x0c || t == 0x0e ||
3501 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
3502 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
3503 t == 0xc1 || t == 0xc4 || t == 0xc6);
3504}
3505
3506static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003507menu(void)
3508{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003509#ifdef CONFIG_FEATURE_SUN_LABEL
3510 if (sun_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003511 puts(_("Command action"));
3512 puts(_("\ta\ttoggle a read only flag")); /* sun */
3513 puts(_("\tb\tedit bsd disklabel"));
3514 puts(_("\tc\ttoggle the mountable flag")); /* sun */
3515 puts(_("\td\tdelete a partition"));
3516 puts(_("\tl\tlist known partition types"));
3517 puts(_("\tm\tprint this menu"));
3518 puts(_("\tn\tadd a new partition"));
3519 puts(_("\to\tcreate a new empty DOS partition table"));
3520 puts(_("\tp\tprint the partition table"));
3521 puts(_("\tq\tquit without saving changes"));
3522 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3523 puts(_("\tt\tchange a partition's system id"));
3524 puts(_("\tu\tchange display/entry units"));
3525 puts(_("\tv\tverify the partition table"));
3526 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003527#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003528 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003529#endif
3530 } else
3531#endif
3532#ifdef CONFIG_FEATURE_SGI_LABEL
3533 if (sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003534 puts(_("Command action"));
3535 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
3536 puts(_("\tb\tedit bootfile entry")); /* sgi */
3537 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
3538 puts(_("\td\tdelete a partition"));
3539 puts(_("\tl\tlist known partition types"));
3540 puts(_("\tm\tprint this menu"));
3541 puts(_("\tn\tadd a new partition"));
3542 puts(_("\to\tcreate a new empty DOS partition table"));
3543 puts(_("\tp\tprint the partition table"));
3544 puts(_("\tq\tquit without saving changes"));
3545 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3546 puts(_("\tt\tchange a partition's system id"));
3547 puts(_("\tu\tchange display/entry units"));
3548 puts(_("\tv\tverify the partition table"));
3549 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003550 } else
3551#endif
3552#ifdef CONFIG_FEATURE_AIX_LABEL
3553 if (aix_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003554 puts(_("Command action"));
3555 puts(_("\tm\tprint this menu"));
3556 puts(_("\to\tcreate a new empty DOS partition table"));
3557 puts(_("\tq\tquit without saving changes"));
3558 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003559 } else
3560#endif
3561 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003562 puts(_("Command action"));
3563 puts(_("\ta\ttoggle a bootable flag"));
3564 puts(_("\tb\tedit bsd disklabel"));
3565 puts(_("\tc\ttoggle the dos compatibility flag"));
3566 puts(_("\td\tdelete a partition"));
3567 puts(_("\tl\tlist known partition types"));
3568 puts(_("\tm\tprint this menu"));
3569 puts(_("\tn\tadd a new partition"));
3570 puts(_("\to\tcreate a new empty DOS partition table"));
3571 puts(_("\tp\tprint the partition table"));
3572 puts(_("\tq\tquit without saving changes"));
3573 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
3574 puts(_("\tt\tchange a partition's system id"));
3575 puts(_("\tu\tchange display/entry units"));
3576 puts(_("\tv\tverify the partition table"));
3577 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003578#ifdef CONFIG_FEATURE_FDISK_ADVANCED
Rob Landleyb73451d2006-02-24 16:29:00 +00003579 puts(_("\tx\textra functionality (experts only)"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003580#endif
3581 }
3582}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003583#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3584
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003585
3586#ifdef CONFIG_FEATURE_FDISK_ADVANCED
3587static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003588xmenu(void)
3589{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003590#ifdef CONFIG_FEATURE_SUN_LABEL
3591 if (sun_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003592 puts(_("Command action"));
3593 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
3594 puts(_("\tc\tchange number of cylinders"));
3595 puts(_("\td\tprint the raw data in the partition table"));
3596 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
3597 puts(_("\th\tchange number of heads"));
3598 puts(_("\ti\tchange interleave factor")); /*sun*/
3599 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
3600 puts(_("\tm\tprint this menu"));
3601 puts(_("\tp\tprint the partition table"));
3602 puts(_("\tq\tquit without saving changes"));
3603 puts(_("\tr\treturn to main menu"));
3604 puts(_("\ts\tchange number of sectors/track"));
3605 puts(_("\tv\tverify the partition table"));
3606 puts(_("\tw\twrite table to disk and exit"));
3607 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003608 } else
3609#endif
3610#ifdef CONFIG_FEATURE_SGI_LABEL
3611 if (sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003612 puts(_("Command action"));
3613 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3614 puts(_("\tc\tchange number of cylinders"));
3615 puts(_("\td\tprint the raw data in the partition table"));
3616 puts(_("\te\tlist extended partitions")); /* !sun */
3617 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3618 puts(_("\th\tchange number of heads"));
3619 puts(_("\tm\tprint this menu"));
3620 puts(_("\tp\tprint the partition table"));
3621 puts(_("\tq\tquit without saving changes"));
3622 puts(_("\tr\treturn to main menu"));
3623 puts(_("\ts\tchange number of sectors/track"));
3624 puts(_("\tv\tverify the partition table"));
3625 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003626 } else
3627#endif
3628#ifdef CONFIG_FEATURE_AIX_LABEL
3629 if (aix_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003630 puts(_("Command action"));
3631 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3632 puts(_("\tc\tchange number of cylinders"));
3633 puts(_("\td\tprint the raw data in the partition table"));
3634 puts(_("\te\tlist extended partitions")); /* !sun */
3635 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
3636 puts(_("\th\tchange number of heads"));
3637 puts(_("\tm\tprint this menu"));
3638 puts(_("\tp\tprint the partition table"));
3639 puts(_("\tq\tquit without saving changes"));
3640 puts(_("\tr\treturn to main menu"));
3641 puts(_("\ts\tchange number of sectors/track"));
3642 puts(_("\tv\tverify the partition table"));
3643 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003644 } else
3645#endif
3646 {
Rob Landleyb73451d2006-02-24 16:29:00 +00003647 puts(_("Command action"));
3648 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
3649 puts(_("\tc\tchange number of cylinders"));
3650 puts(_("\td\tprint the raw data in the partition table"));
3651 puts(_("\te\tlist extended partitions")); /* !sun */
3652 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003653#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00003654 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003655#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00003656 puts(_("\th\tchange number of heads"));
3657 puts(_("\tm\tprint this menu"));
3658 puts(_("\tp\tprint the partition table"));
3659 puts(_("\tq\tquit without saving changes"));
3660 puts(_("\tr\treturn to main menu"));
3661 puts(_("\ts\tchange number of sectors/track"));
3662 puts(_("\tv\tverify the partition table"));
3663 puts(_("\tw\twrite table to disk and exit"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003664 }
3665}
3666#endif /* ADVANCED mode */
3667
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003668#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003669static const struct systypes *
Rob Landleyb73451d2006-02-24 16:29:00 +00003670get_sys_types(void)
3671{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003672 return (
3673#ifdef CONFIG_FEATURE_SUN_LABEL
3674 sun_label ? sun_sys_types :
3675#endif
3676#ifdef CONFIG_FEATURE_SGI_LABEL
3677 sgi_label ? sgi_sys_types :
3678#endif
3679 i386_sys_types);
3680}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003681#else
3682#define get_sys_types() i386_sys_types
3683#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003684
3685static const char *partition_type(unsigned char type)
3686{
3687 int i;
3688 const struct systypes *types = get_sys_types();
3689
Rob Landleyb73451d2006-02-24 16:29:00 +00003690 for (i = 0; types[i].name; i++)
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003691 if ((unsigned char )types[i].name[0] == type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003692 return types[i].name + 1;
3693
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003694 return _("Unknown");
3695}
3696
3697
3698#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3699static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003700get_sysid(int i)
3701{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003702 return (
3703#ifdef CONFIG_FEATURE_SUN_LABEL
3704 sun_label ? sunlabel->infos[i].id :
3705#endif
3706#ifdef CONFIG_FEATURE_SGI_LABEL
3707 sgi_label ? sgi_get_sysid(i) :
3708#endif
3709 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003710}
3711
3712void list_types(const struct systypes *sys)
3713{
3714 uint last[4], done = 0, next = 0, size;
3715 int i;
3716
3717 for (i = 0; sys[i].name; i++);
3718 size = i;
3719
3720 for (i = 3; i >= 0; i--)
3721 last[3 - i] = done += (size + i - done) / (i + 1);
3722 i = done = 0;
3723
3724 do {
3725 printf("%c%2x %-15.15s", i ? ' ' : '\n',
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00003726 (unsigned char)sys[next].name[0],
3727 partition_type((unsigned char)sys[next].name[0]));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003728 next = last[i++] + done;
3729 if (i > 3 || next >= last[i]) {
3730 i = 0;
3731 next = ++done;
3732 }
3733 } while (done < last[0]);
3734 putchar('\n');
3735}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003736#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003737
3738static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003739is_cleared_partition(const struct partition *p)
3740{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003741 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
3742 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
3743 get_start_sect(p) || get_nr_sects(p));
3744}
3745
3746static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003747clear_partition(struct partition *p)
3748{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003749 if (!p)
3750 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003751 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003752}
3753
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003754#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003755static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003756set_partition(int i, int doext, off_t start, off_t stop, int sysid)
3757{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003758 struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00003759 off_t offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003760
3761 if (doext) {
3762 p = ptes[i].ext_pointer;
3763 offset = extended_offset;
3764 } else {
3765 p = ptes[i].part_table;
3766 offset = ptes[i].offset;
3767 }
3768 p->boot_ind = 0;
3769 p->sys_ind = sysid;
3770 set_start_sect(p, start - offset);
3771 set_nr_sects(p, stop - start + 1);
3772 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
3773 start = heads*sectors*1024 - 1;
3774 set_hsc(p->head, p->sector, p->cyl, start);
3775 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
3776 stop = heads*sectors*1024 - 1;
3777 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
3778 ptes[i].changed = 1;
3779}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003780#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003781
3782static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003783test_c(const char **m, const char *mesg)
3784{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003785 int val = 0;
3786 if (!*m)
3787 fprintf(stderr, _("You must set"));
3788 else {
3789 fprintf(stderr, " %s", *m);
3790 val = 1;
3791 }
3792 *m = mesg;
3793 return val;
3794}
3795
3796static int
Rob Landleyb73451d2006-02-24 16:29:00 +00003797warn_geometry(void)
3798{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003799 const char *m = NULL;
3800 int prev = 0;
3801
3802 if (!heads)
3803 prev = test_c(&m, _("heads"));
3804 if (!sectors)
3805 prev = test_c(&m, _("sectors"));
3806 if (!cylinders)
3807 prev = test_c(&m, _("cylinders"));
3808 if (!m)
3809 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003810
3811 fprintf(stderr, "%s%s.\n"
3812#ifdef CONFIG_FEATURE_FDISK_WRITABLE
3813 "You can do this from the extra functions menu.\n"
3814#endif
3815 , prev ? _(" and ") : " ", m);
3816
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003817 return 1;
3818}
3819
3820static void update_units(void)
3821{
3822 int cyl_units = heads * sectors;
3823
3824 if (display_in_cyl_units && cyl_units)
3825 units_per_sector = cyl_units;
3826 else
3827 units_per_sector = 1; /* in sectors */
3828}
3829
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003830#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003831static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003832warn_cylinders(void)
3833{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003834 if (dos_label && cylinders > 1024 && !nowarn)
3835 fprintf(stderr, _("\n"
3836"The number of cylinders for this disk is set to %d.\n"
3837"There is nothing wrong with that, but this is larger than 1024,\n"
3838"and could in certain setups cause problems with:\n"
3839"1) software that runs at boot time (e.g., old versions of LILO)\n"
3840"2) booting and partitioning software from other OSs\n"
3841" (e.g., DOS FDISK, OS/2 FDISK)\n"),
3842 cylinders);
3843}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003844#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003845
3846static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003847read_extended(int ext)
3848{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003849 int i;
3850 struct pte *pex;
3851 struct partition *p, *q;
3852
3853 ext_index = ext;
3854 pex = &ptes[ext];
3855 pex->ext_pointer = pex->part_table;
3856
3857 p = pex->part_table;
3858 if (!get_start_sect(p)) {
3859 fprintf(stderr,
3860 _("Bad offset in primary extended partition\n"));
3861 return;
3862 }
3863
Rob Landleyb73451d2006-02-24 16:29:00 +00003864 while (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003865 struct pte *pe = &ptes[partitions];
3866
3867 if (partitions >= MAXIMUM_PARTS) {
3868 /* This is not a Linux restriction, but
3869 this program uses arrays of size MAXIMUM_PARTS.
3870 Do not try to `improve' this test. */
3871 struct pte *pre = &ptes[partitions-1];
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003872#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003873 fprintf(stderr,
3874 _("Warning: deleting partitions after %d\n"),
3875 partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003876 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003877#endif
3878 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003879 return;
3880 }
3881
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003882 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003883
3884 if (!extended_offset)
3885 extended_offset = get_start_sect(p);
3886
3887 q = p = pt_offset(pe->sectorbuffer, 0);
3888 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00003889 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003890 if (pe->ext_pointer)
3891 fprintf(stderr,
3892 _("Warning: extra link "
3893 "pointer in partition table"
3894 " %d\n"), partitions + 1);
3895 else
3896 pe->ext_pointer = p;
3897 } else if (p->sys_ind) {
3898 if (pe->part_table)
3899 fprintf(stderr,
3900 _("Warning: ignoring extra "
3901 "data in partition table"
3902 " %d\n"), partitions + 1);
3903 else
3904 pe->part_table = p;
3905 }
3906 }
3907
3908 /* very strange code here... */
3909 if (!pe->part_table) {
3910 if (q != pe->ext_pointer)
3911 pe->part_table = q;
3912 else
3913 pe->part_table = q + 1;
3914 }
3915 if (!pe->ext_pointer) {
3916 if (q != pe->part_table)
3917 pe->ext_pointer = q;
3918 else
3919 pe->ext_pointer = q + 1;
3920 }
3921
3922 p = pe->ext_pointer;
3923 partitions++;
3924 }
3925
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003926#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003927 /* remove empty links */
3928 remove:
3929 for (i = 4; i < partitions; i++) {
3930 struct pte *pe = &ptes[i];
3931
3932 if (!get_nr_sects(pe->part_table) &&
Rob Landleyb73451d2006-02-24 16:29:00 +00003933 (partitions > 5 || ptes[4].part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003934 printf("omitting empty partition (%d)\n", i+1);
3935 delete_partition(i);
3936 goto remove; /* numbering changed */
3937 }
3938 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003939#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003940}
3941
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003942#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003943static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003944create_doslabel(void)
3945{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003946 int i;
3947
3948 fprintf(stderr,
3949 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
3950 "until you decide to write them. After that, of course, the previous\n"
3951 "content won't be recoverable.\n\n"));
3952#ifdef CONFIG_FEATURE_SUN_LABEL
3953 sun_nolabel(); /* otherwise always recognised as sun */
3954#endif
3955#ifdef CONFIG_FEATURE_SGI_LABEL
3956 sgi_nolabel(); /* otherwise always recognised as sgi */
3957#endif
3958#ifdef CONFIG_FEATURE_AIX_LABEL
3959 aix_label = 0;
3960#endif
3961#ifdef CONFIG_FEATURE_OSF_LABEL
3962 osf_label = 0;
3963 possibly_osf_label = 0;
3964#endif
3965 partitions = 4;
3966
3967 for (i = 510-64; i < 510; i++)
3968 MBRbuffer[i] = 0;
3969 write_part_table_flag(MBRbuffer);
3970 extended_offset = 0;
3971 set_all_unchanged();
3972 set_changed(0);
3973 get_boot(create_empty_dos);
3974}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003975#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003976
3977static void
Rob Landleyb73451d2006-02-24 16:29:00 +00003978get_sectorsize(void)
3979{
3980 if (!user_set_sector_size
3981 && get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003982 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"),
Rob Landleyb73451d2006-02-24 16:29:00 +00003987 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003988 }
3989}
3990
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00003991static inline void
Rob Landleyb73451d2006-02-24 16:29:00 +00003992get_kernel_geometry(void)
3993{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00003994 struct hd_geometry geometry;
3995
3996 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
3997 kern_heads = geometry.heads;
3998 kern_sectors = geometry.sectors;
3999 /* never use geometry.cylinders - it is truncated */
4000 }
4001}
4002
4003static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004004get_partition_table_geometry(void)
4005{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00004006 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004007 struct partition *p;
4008 int i, h, s, hh, ss;
4009 int first = 1;
4010 int bad = 0;
4011
Eric Andersen3496fdc2006-01-30 23:09:20 +00004012 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004013 return;
4014
4015 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00004016 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004017 p = pt_offset(bufp, i);
4018 if (p->sys_ind != 0) {
4019 h = p->end_head + 1;
4020 s = (p->end_sector & 077);
4021 if (first) {
4022 hh = h;
4023 ss = s;
4024 first = 0;
4025 } else if (hh != h || ss != s)
4026 bad = 1;
4027 }
4028 }
4029
4030 if (!first && !bad) {
4031 pt_heads = hh;
4032 pt_sectors = ss;
4033 }
4034}
4035
Rob Landleyb73451d2006-02-24 16:29:00 +00004036static void
4037get_geometry(void)
4038{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004039 int sec_fac;
Eric Andersen040f4402003-07-30 08:40:37 +00004040 unsigned long long bytes; /* really u64 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004041
4042 get_sectorsize();
4043 sec_fac = sector_size / 512;
4044#ifdef CONFIG_FEATURE_SUN_LABEL
4045 guess_device_type();
4046#endif
4047 heads = cylinders = sectors = 0;
4048 kern_heads = kern_sectors = 0;
4049 pt_heads = pt_sectors = 0;
4050
4051 get_kernel_geometry();
4052 get_partition_table_geometry();
4053
4054 heads = user_heads ? user_heads :
4055 pt_heads ? pt_heads :
4056 kern_heads ? kern_heads : 255;
4057 sectors = user_sectors ? user_sectors :
4058 pt_sectors ? pt_sectors :
4059 kern_sectors ? kern_sectors : 63;
Eric Andersen040f4402003-07-30 08:40:37 +00004060 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
4061 /* got bytes */
4062 } else {
4063 unsigned long longsectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004064
4065 if (ioctl(fd, BLKGETSIZE, &longsectors))
4066 longsectors = 0;
Eric Andersen040f4402003-07-30 08:40:37 +00004067 bytes = ((unsigned long long) longsectors) << 9;
4068 }
4069
4070 total_number_of_sectors = (bytes >> 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004071
4072 sector_offset = 1;
4073 if (dos_compatible_flag)
4074 sector_offset = sectors;
4075
Eric Andersen040f4402003-07-30 08:40:37 +00004076 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004077 if (!cylinders)
4078 cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004079}
4080
4081/*
4082 * Read MBR. Returns:
4083 * -1: no 0xaa55 flag present (possibly entire disk BSD)
4084 * 0: found or created label
4085 * 1: I/O error
4086 */
Rob Landleyb73451d2006-02-24 16:29:00 +00004087static int
4088get_boot(enum action what)
4089{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004090 int i;
4091
4092 partitions = 4;
4093
4094 for (i = 0; i < 4; i++) {
4095 struct pte *pe = &ptes[i];
4096
4097 pe->part_table = pt_offset(MBRbuffer, i);
4098 pe->ext_pointer = NULL;
4099 pe->offset = 0;
4100 pe->sectorbuffer = MBRbuffer;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004101#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004102 pe->changed = (what == create_empty_dos);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004103#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004104 }
4105
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004106#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004107 if (what == create_empty_sun && check_sun_label())
4108 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004109#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004110
4111 memset(MBRbuffer, 0, 512);
4112
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004113#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004114 if (what == create_empty_dos)
4115 goto got_dos_table; /* skip reading disk */
4116
4117 if ((fd = open(disk_device, type_open)) < 0) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004118 if ((fd = open(disk_device, O_RDONLY)) < 0) {
4119 if (what == try_only)
4120 return 1;
4121 fdisk_fatal(unable_to_open);
4122 } else
4123 printf(_("You will not be able to write "
4124 "the partition table.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004125 }
4126
4127 if (512 != read(fd, MBRbuffer, 512)) {
4128 if (what == try_only)
4129 return 1;
4130 fdisk_fatal(unable_to_read);
4131 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004132#else
4133 if ((fd = open(disk_device, O_RDONLY)) < 0)
4134 return 1;
4135 if (512 != read(fd, MBRbuffer, 512))
4136 return 1;
4137#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004138
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004139 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004140
4141 update_units();
4142
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004143#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004144 if (check_sun_label())
4145 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004146#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004147
4148#ifdef CONFIG_FEATURE_SGI_LABEL
4149 if (check_sgi_label())
4150 return 0;
4151#endif
4152
4153#ifdef CONFIG_FEATURE_AIX_LABEL
4154 if (check_aix_label())
4155 return 0;
4156#endif
4157
4158#ifdef CONFIG_FEATURE_OSF_LABEL
4159 if (check_osf_label()) {
4160 possibly_osf_label = 1;
4161 if (!valid_part_table_flag(MBRbuffer)) {
4162 osf_label = 1;
4163 return 0;
4164 }
4165 printf(_("This disk has both DOS and BSD magic.\n"
4166 "Give the 'b' command to go to BSD mode.\n"));
4167 }
4168#endif
4169
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004170#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Rob Landleyb73451d2006-02-24 16:29:00 +00004171 got_dos_table:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004172#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004173
4174 if (!valid_part_table_flag(MBRbuffer)) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004175#ifndef CONFIG_FEATURE_FDISK_WRITABLE
4176 return -1;
4177#else
Rob Landleyb73451d2006-02-24 16:29:00 +00004178 switch (what) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004179 case fdisk:
4180 fprintf(stderr,
4181 _("Device contains neither a valid DOS "
4182 "partition table, nor Sun, SGI or OSF "
4183 "disklabel\n"));
4184#ifdef __sparc__
4185#ifdef CONFIG_FEATURE_SUN_LABEL
4186 create_sunlabel();
4187#endif
4188#else
4189 create_doslabel();
4190#endif
4191 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004192 case try_only:
4193 return -1;
4194 case create_empty_dos:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004195#ifdef CONFIG_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004196 case create_empty_sun:
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004197#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004198 break;
4199 default:
4200 fprintf(stderr, _("Internal error\n"));
4201 exit(1);
4202 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004203#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004204 }
4205
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004206#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004207 warn_cylinders();
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004208#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004209 warn_geometry();
4210
4211 for (i = 0; i < 4; i++) {
4212 struct pte *pe = &ptes[i];
4213
Rob Landleyb73451d2006-02-24 16:29:00 +00004214 if (IS_EXTENDED(pe->part_table->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004215 if (partitions != 4)
4216 fprintf(stderr, _("Ignoring extra extended "
4217 "partition %d\n"), i + 1);
4218 else
4219 read_extended(i);
4220 }
4221 }
4222
4223 for (i = 3; i < partitions; i++) {
4224 struct pte *pe = &ptes[i];
4225
4226 if (!valid_part_table_flag(pe->sectorbuffer)) {
4227 fprintf(stderr,
4228 _("Warning: invalid flag 0x%04x of partition "
4229 "table %d will be corrected by w(rite)\n"),
4230 part_table_flag(pe->sectorbuffer), i + 1);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004231#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004232 pe->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004233#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004234 }
4235 }
4236
4237 return 0;
4238}
4239
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004240#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004241/*
4242 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
4243 * If the user hits Enter, DFLT is returned.
4244 * Answers like +10 are interpreted as offsets from BASE.
4245 *
4246 * There is no default if DFLT is not between LOW and HIGH.
4247 */
4248static uint
4249read_int(uint low, uint dflt, uint high, uint base, char *mesg)
4250{
4251 uint i;
4252 int default_ok = 1;
4253 static char *ms = NULL;
4254 static int mslen = 0;
4255
4256 if (!ms || strlen(mesg)+100 > mslen) {
4257 mslen = strlen(mesg)+200;
4258 ms = xrealloc(ms,mslen);
4259 }
4260
4261 if (dflt < low || dflt > high)
4262 default_ok = 0;
4263
4264 if (default_ok)
Eric Andersen040f4402003-07-30 08:40:37 +00004265 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004266 mesg, low, high, dflt);
4267 else
Rob Landleyb73451d2006-02-24 16:29:00 +00004268 snprintf(ms, mslen, "%s (%u-%u): ", mesg, low, high);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004269
4270 while (1) {
4271 int use_default = default_ok;
4272
4273 /* ask question and read answer */
4274 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
Rob Landleyb73451d2006-02-24 16:29:00 +00004275 && *line_ptr != '-' && *line_ptr != '+')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004276 continue;
4277
Eric Andersen84bdea82004-05-19 10:49:17 +00004278 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00004279 int minus = (*line_ptr == '-');
4280 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00004281
Rob Landleyb73451d2006-02-24 16:29:00 +00004282 i = atoi(line_ptr+1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00004283
Rob Landleyb73451d2006-02-24 16:29:00 +00004284 while (isdigit(*++line_ptr))
4285 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00004286
Rob Landleyb73451d2006-02-24 16:29:00 +00004287 switch (*line_ptr) {
4288 case 'c':
4289 case 'C':
4290 if (!display_in_cyl_units)
4291 i *= heads * sectors;
4292 break;
4293 case 'K':
4294 absolute = 1024;
4295 break;
4296 case 'k':
4297 absolute = 1000;
4298 break;
4299 case 'm':
4300 case 'M':
4301 absolute = 1000000;
4302 break;
4303 case 'g':
4304 case 'G':
4305 absolute = 1000000000;
4306 break;
4307 default:
4308 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004309 }
Rob Landleyb73451d2006-02-24 16:29:00 +00004310 if (absolute) {
4311 unsigned long long bytes;
4312 unsigned long unit;
4313
4314 bytes = (unsigned long long) i * absolute;
4315 unit = sector_size * units_per_sector;
4316 bytes += unit/2; /* round */
4317 bytes /= unit;
4318 i = bytes;
4319 }
4320 if (minus)
4321 i = -i;
4322 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00004323 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004324 i = atoi(line_ptr);
4325 while (isdigit(*line_ptr)) {
4326 line_ptr++;
4327 use_default = 0;
4328 }
4329 }
4330 if (use_default)
Eric Andersen040f4402003-07-30 08:40:37 +00004331 printf(_("Using default value %u\n"), i = dflt);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004332 if (i >= low && i <= high)
4333 break;
4334 else
4335 printf(_("Value out of range.\n"));
4336 }
4337 return i;
4338}
4339
Rob Landleyb73451d2006-02-24 16:29:00 +00004340static int
4341get_partition(int warn, int max)
4342{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004343 struct pte *pe;
4344 int i;
4345
4346 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
4347 pe = &ptes[i];
4348
4349 if (warn) {
4350 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
4351#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00004352 || (sun_label &&
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004353 (!sunlabel->partitions[i].num_sectors ||
4354 !sunlabel->infos[i].id))
4355#endif
4356#ifdef CONFIG_FEATURE_SGI_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00004357 || (sgi_label && (!sgi_get_num_sectors(i)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004358#endif
4359 )
4360 fprintf(stderr,
4361 _("Warning: partition %d has empty type\n"),
4362 i+1);
4363 }
4364 return i;
4365}
4366
4367static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004368get_existing_partition(int warn, int max)
4369{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004370 int pno = -1;
4371 int i;
4372
4373 for (i = 0; i < max; i++) {
4374 struct pte *pe = &ptes[i];
4375 struct partition *p = pe->part_table;
4376
4377 if (p && !is_cleared_partition(p)) {
4378 if (pno >= 0)
4379 goto not_unique;
4380 pno = i;
4381 }
4382 }
4383 if (pno >= 0) {
4384 printf(_("Selected partition %d\n"), pno+1);
4385 return pno;
4386 }
4387 printf(_("No partition is defined yet!\n"));
4388 return -1;
4389
4390 not_unique:
4391 return get_partition(warn, max);
4392}
4393
4394static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004395get_nonexisting_partition(int warn, int max)
4396{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004397 int pno = -1;
4398 int i;
4399
4400 for (i = 0; i < max; i++) {
4401 struct pte *pe = &ptes[i];
4402 struct partition *p = pe->part_table;
4403
4404 if (p && is_cleared_partition(p)) {
4405 if (pno >= 0)
4406 goto not_unique;
4407 pno = i;
4408 }
4409 }
4410 if (pno >= 0) {
4411 printf(_("Selected partition %d\n"), pno+1);
4412 return pno;
4413 }
4414 printf(_("All primary partitions have been defined already!\n"));
4415 return -1;
4416
4417 not_unique:
4418 return get_partition(warn, max);
4419}
4420
4421
4422void change_units(void)
4423{
4424 display_in_cyl_units = !display_in_cyl_units;
4425 update_units();
4426 printf(_("Changing display/entry units to %s\n"),
4427 str_units(PLURAL));
4428}
4429
4430static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004431toggle_active(int i)
4432{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004433 struct pte *pe = &ptes[i];
4434 struct partition *p = pe->part_table;
4435
Rob Landleyb73451d2006-02-24 16:29:00 +00004436 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004437 fprintf(stderr,
4438 _("WARNING: Partition %d is an extended partition\n"),
4439 i + 1);
4440 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
4441 pe->changed = 1;
4442}
4443
4444static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004445toggle_dos_compatibility_flag(void)
4446{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004447 dos_compatible_flag = ~dos_compatible_flag;
4448 if (dos_compatible_flag) {
4449 sector_offset = sectors;
4450 printf(_("DOS Compatibility flag is set\n"));
4451 }
4452 else {
4453 sector_offset = 1;
4454 printf(_("DOS Compatibility flag is not set\n"));
4455 }
4456}
4457
4458static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004459delete_partition(int i)
4460{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004461 struct pte *pe = &ptes[i];
4462 struct partition *p = pe->part_table;
4463 struct partition *q = pe->ext_pointer;
4464
4465/* Note that for the fifth partition (i == 4) we don't actually
4466 * decrement partitions.
4467 */
4468
4469 if (warn_geometry())
4470 return; /* C/H/S not set */
4471 pe->changed = 1;
4472
4473#ifdef CONFIG_FEATURE_SUN_LABEL
4474 if (sun_label) {
4475 sun_delete_partition(i);
4476 return;
4477 }
4478#endif
4479#ifdef CONFIG_FEATURE_SGI_LABEL
4480 if (sgi_label) {
4481 sgi_delete_partition(i);
4482 return;
4483 }
4484#endif
4485
4486 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004487 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004488 partitions = 4;
4489 ptes[ext_index].ext_pointer = NULL;
4490 extended_offset = 0;
4491 }
4492 clear_partition(p);
4493 return;
4494 }
4495
4496 if (!q->sys_ind && i > 4) {
4497 /* the last one in the chain - just delete */
4498 --partitions;
4499 --i;
4500 clear_partition(ptes[i].ext_pointer);
4501 ptes[i].changed = 1;
4502 } else {
4503 /* not the last one - further ones will be moved down */
4504 if (i > 4) {
4505 /* delete this link in the chain */
4506 p = ptes[i-1].ext_pointer;
4507 *p = *q;
4508 set_start_sect(p, get_start_sect(q));
4509 set_nr_sects(p, get_nr_sects(q));
4510 ptes[i-1].changed = 1;
4511 } else if (partitions > 5) { /* 5 will be moved to 4 */
4512 /* the first logical in a longer chain */
4513 pe = &ptes[5];
4514
4515 if (pe->part_table) /* prevent SEGFAULT */
4516 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00004517 get_partition_start(pe) -
4518 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004519 pe->offset = extended_offset;
4520 pe->changed = 1;
4521 }
4522
4523 if (partitions > 5) {
4524 partitions--;
4525 while (i < partitions) {
4526 ptes[i] = ptes[i+1];
4527 i++;
4528 }
4529 } else
4530 /* the only logical: clear only */
4531 clear_partition(ptes[i].part_table);
4532 }
4533}
4534
4535static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004536change_sysid(void)
4537{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004538 int i, sys, origsys;
4539 struct partition *p;
4540
Eric Andersen040f4402003-07-30 08:40:37 +00004541#ifdef CONFIG_FEATURE_SGI_LABEL
4542 /* If sgi_label then don't use get_existing_partition,
4543 let the user select a partition, since get_existing_partition()
4544 only works for Linux like partition tables. */
4545 if (!sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004546 i = get_existing_partition(0, partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00004547 } else {
4548 i = get_partition(0, partitions);
4549 }
4550#else
4551 i = get_existing_partition(0, partitions);
4552#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004553 if (i == -1)
4554 return;
4555 p = ptes[i].part_table;
4556 origsys = sys = get_sysid(i);
4557
4558 /* if changing types T to 0 is allowed, then
4559 the reverse change must be allowed, too */
4560 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
4561 printf(_("Partition %d does not exist yet!\n"), i + 1);
4562 else while (1) {
4563 sys = read_hex (get_sys_types());
4564
4565 if (!sys && !sgi_label && !sun_label) {
4566 printf(_("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00004567 "(but not to Linux). Having partitions of\n"
4568 "type 0 is probably unwise. You can delete\n"
4569 "a partition using the `d' command.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004570 /* break; */
4571 }
4572
4573 if (!sun_label && !sgi_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00004574 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004575 printf(_("You cannot change a partition into"
Rob Landleyb73451d2006-02-24 16:29:00 +00004576 " an extended one or vice versa\n"
4577 "Delete it first.\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004578 break;
4579 }
4580 }
4581
4582 if (sys < 256) {
4583#ifdef CONFIG_FEATURE_SUN_LABEL
4584 if (sun_label && i == 2 && sys != WHOLE_DISK)
4585 printf(_("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004586 "as Whole disk (5),\n"
4587 "as SunOS/Solaris expects it and "
4588 "even Linux likes it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004589#endif
4590#ifdef CONFIG_FEATURE_SGI_LABEL
4591 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
4592 || (i == 8 && sys != 0)))
4593 printf(_("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00004594 "as volume header (0),\nand "
4595 "partition 11 as entire volume (6)"
4596 "as IRIX expects it.\n\n"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004597#endif
4598 if (sys == origsys)
4599 break;
4600#ifdef CONFIG_FEATURE_SUN_LABEL
4601 if (sun_label) {
4602 sun_change_sysid(i, sys);
4603 } else
4604#endif
4605#ifdef CONFIG_FEATURE_SGI_LABEL
4606 if (sgi_label) {
4607 sgi_change_sysid(i, sys);
4608 } else
4609#endif
4610 p->sys_ind = sys;
Rob Landleyb73451d2006-02-24 16:29:00 +00004611 printf(_("Changed system type of partition %d "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004612 "to %x (%s)\n"), i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004613 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004614 ptes[i].changed = 1;
4615 if (is_dos_partition(origsys) ||
Rob Landleyb73451d2006-02-24 16:29:00 +00004616 is_dos_partition(sys))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004617 dos_changed = 1;
4618 break;
4619 }
4620 }
4621}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004622#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
4623
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004624
4625/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
4626 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
4627 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
4628 * Lubkin Oct. 1991). */
4629
Rob Landleyb73451d2006-02-24 16:29:00 +00004630static void
4631long2chs(ulong ls, uint *c, uint *h, uint *s)
4632{
4633 int spc = heads * sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004634
4635 *c = ls / spc;
4636 ls = ls % spc;
4637 *h = ls / sectors;
4638 *s = ls % sectors + 1; /* sectors count from 1 */
4639}
4640
Rob Landleyb73451d2006-02-24 16:29:00 +00004641static void
4642check_consistency(const struct partition *p, int partition)
4643{
4644 uint pbc, pbh, pbs; /* physical beginning c, h, s */
4645 uint pec, peh, pes; /* physical ending c, h, s */
4646 uint lbc, lbh, lbs; /* logical beginning c, h, s */
4647 uint lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004648
4649 if (!heads || !sectors || (partition >= 4))
4650 return; /* do not check extended partitions */
4651
4652/* physical beginning c, h, s */
4653 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
4654 pbh = p->head;
4655 pbs = p->sector & 0x3f;
4656
4657/* physical ending c, h, s */
4658 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
4659 peh = p->end_head;
4660 pes = p->end_sector & 0x3f;
4661
4662/* compute logical beginning (c, h, s) */
4663 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
4664
4665/* compute logical ending (c, h, s) */
4666 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
4667
4668/* Same physical / logical beginning? */
4669 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
4670 printf(_("Partition %d has different physical/logical "
4671 "beginnings (non-Linux?):\n"), partition + 1);
4672 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4673 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
4674 }
4675
4676/* Same physical / logical ending? */
4677 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
4678 printf(_("Partition %d has different physical/logical "
4679 "endings:\n"), partition + 1);
4680 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4681 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
4682 }
4683
4684#if 0
4685/* Beginning on cylinder boundary? */
4686 if (pbh != !pbc || pbs != 1) {
4687 printf(_("Partition %i does not start on cylinder "
4688 "boundary:\n"), partition + 1);
4689 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
4690 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
4691 }
4692#endif
4693
4694/* Ending on cylinder boundary? */
4695 if (peh != (heads - 1) || pes != sectors) {
Eric Andersen84bdea82004-05-19 10:49:17 +00004696 printf(_("Partition %i does not end on cylinder boundary.\n"),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004697 partition + 1);
4698#if 0
4699 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
4700 printf(_("should be (%d, %d, %d)\n"),
4701 pec, heads - 1, sectors);
4702#endif
4703 }
4704}
4705
4706static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004707list_disk_geometry(void)
4708{
Eric Andersen040f4402003-07-30 08:40:37 +00004709 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004710 long megabytes = bytes/1000000;
4711
4712 if (megabytes < 10000)
4713 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004714 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004715 else
4716 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004717 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004718 printf(_("%d heads, %d sectors/track, %d cylinders"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004719 heads, sectors, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004720 if (units_per_sector == 1)
Eric Andersen040f4402003-07-30 08:40:37 +00004721 printf(_(", total %llu sectors"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004722 total_number_of_sectors / (sector_size/512));
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004723 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004724 str_units(PLURAL),
4725 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004726}
4727
4728/*
4729 * Check whether partition entries are ordered by their starting positions.
4730 * Return 0 if OK. Return i if partition i should have been earlier.
4731 * Two separate checks: primary and logical partitions.
4732 */
4733static int
Rob Landleyb73451d2006-02-24 16:29:00 +00004734wrong_p_order(int *prev)
4735{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004736 const struct pte *pe;
4737 const struct partition *p;
Eric Andersend9261492004-06-28 23:50:31 +00004738 off_t last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004739 int i, last_i = 0;
4740
4741 for (i = 0 ; i < partitions; i++) {
4742 if (i == 4) {
4743 last_i = 4;
4744 last_p_start_pos = 0;
4745 }
4746 pe = &ptes[i];
4747 if ((p = pe->part_table)->sys_ind) {
4748 p_start_pos = get_partition_start(pe);
4749
4750 if (last_p_start_pos > p_start_pos) {
4751 if (prev)
4752 *prev = last_i;
4753 return i;
4754 }
4755
4756 last_p_start_pos = p_start_pos;
4757 last_i = i;
4758 }
4759 }
4760 return 0;
4761}
4762
4763#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4764/*
4765 * Fix the chain of logicals.
4766 * extended_offset is unchanged, the set of sectors used is unchanged
4767 * The chain is sorted so that sectors increase, and so that
4768 * starting sectors increase.
4769 *
4770 * After this it may still be that cfdisk doesnt like the table.
4771 * (This is because cfdisk considers expanded parts, from link to
4772 * end of partition, and these may still overlap.)
4773 * Now
4774 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
4775 * may help.
4776 */
4777static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004778fix_chain_of_logicals(void)
4779{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004780 int j, oj, ojj, sj, sjj;
4781 struct partition *pj,*pjj,tmp;
4782
4783 /* Stage 1: sort sectors but leave sector of part 4 */
4784 /* (Its sector is the global extended_offset.) */
4785 stage1:
4786 for (j = 5; j < partitions-1; j++) {
4787 oj = ptes[j].offset;
4788 ojj = ptes[j+1].offset;
4789 if (oj > ojj) {
4790 ptes[j].offset = ojj;
4791 ptes[j+1].offset = oj;
4792 pj = ptes[j].part_table;
4793 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
4794 pjj = ptes[j+1].part_table;
4795 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
4796 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004797 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004798 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00004799 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004800 goto stage1;
4801 }
4802 }
4803
4804 /* Stage 2: sort starting sectors */
4805 stage2:
4806 for (j = 4; j < partitions-1; j++) {
4807 pj = ptes[j].part_table;
4808 pjj = ptes[j+1].part_table;
4809 sj = get_start_sect(pj);
4810 sjj = get_start_sect(pjj);
4811 oj = ptes[j].offset;
4812 ojj = ptes[j+1].offset;
4813 if (oj+sj > ojj+sjj) {
4814 tmp = *pj;
4815 *pj = *pjj;
4816 *pjj = tmp;
4817 set_start_sect(pj, ojj+sjj-oj);
4818 set_start_sect(pjj, oj+sj-ojj);
4819 goto stage2;
4820 }
4821 }
4822
4823 /* Probably something was changed */
4824 for (j = 4; j < partitions; j++)
4825 ptes[j].changed = 1;
4826}
4827
4828
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004829static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004830fix_partition_table_order(void)
4831{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004832 struct pte *pei, *pek;
4833 int i,k;
4834
4835 if (!wrong_p_order(NULL)) {
4836 printf(_("Nothing to do. Ordering is correct already.\n\n"));
4837 return;
4838 }
4839
4840 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
4841 /* partition i should have come earlier, move it */
4842 /* We have to move data in the MBR */
4843 struct partition *pi, *pk, *pe, pbuf;
4844 pei = &ptes[i];
4845 pek = &ptes[k];
4846
4847 pe = pei->ext_pointer;
4848 pei->ext_pointer = pek->ext_pointer;
4849 pek->ext_pointer = pe;
4850
4851 pi = pei->part_table;
4852 pk = pek->part_table;
4853
4854 memmove(&pbuf, pi, sizeof(struct partition));
4855 memmove(pi, pk, sizeof(struct partition));
4856 memmove(pk, &pbuf, sizeof(struct partition));
4857
4858 pei->changed = pek->changed = 1;
4859 }
4860
4861 if (i)
4862 fix_chain_of_logicals();
4863
4864 printf("Done.\n");
4865
4866}
4867#endif
4868
4869static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004870list_table(int xtra)
4871{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004872 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004873 int i, w;
4874
4875#ifdef CONFIG_FEATURE_SUN_LABEL
4876 if (sun_label) {
4877 sun_list_table(xtra);
4878 return;
4879 }
4880#endif
4881
4882#ifdef CONFIG_FEATURE_SGI_LABEL
4883 if (sgi_label) {
4884 sgi_list_table(xtra);
4885 return;
4886 }
4887#endif
4888
4889 list_disk_geometry();
4890
4891#ifdef CONFIG_FEATURE_OSF_LABEL
4892 if (osf_label) {
4893 xbsd_print_disklabel(xtra);
4894 return;
4895 }
4896#endif
4897
4898 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
4899 but if the device name ends in a digit, say /dev/foo1,
4900 then the partition is called /dev/foo1p3. */
4901 w = strlen(disk_device);
4902 if (w && isdigit(disk_device[w-1]))
4903 w++;
4904 if (w < 5)
4905 w = 5;
4906
4907 printf(_("%*s Boot Start End Blocks Id System\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00004908 w+1, _("Device"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004909
4910 for (i = 0; i < partitions; i++) {
4911 const struct pte *pe = &ptes[i];
4912
4913 p = pe->part_table;
4914 if (p && !is_cleared_partition(p)) {
Eric Andersend9261492004-06-28 23:50:31 +00004915 off_t psects = get_nr_sects(p);
4916 off_t pblocks = psects;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004917 unsigned int podd = 0;
4918
4919 if (sector_size < 1024) {
4920 pblocks /= (1024 / sector_size);
4921 podd = psects % (1024 / sector_size);
4922 }
4923 if (sector_size > 1024)
4924 pblocks *= (sector_size / 1024);
4925 printf(
Rob Landleyb73451d2006-02-24 16:29:00 +00004926 "%s %c %11llu %11llu %11llu%c %2x %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004927 partname(disk_device, i+1, w+2),
4928/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
4929 ? '*' : '?',
Eric Andersend9261492004-06-28 23:50:31 +00004930/* start */ (unsigned long long) cround(get_partition_start(pe)),
4931/* end */ (unsigned long long) cround(get_partition_start(pe) + psects
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004932 - (psects ? 1 : 0)),
Eric Andersend9261492004-06-28 23:50:31 +00004933/* odd flag on end */ (unsigned long long) pblocks, podd ? '+' : ' ',
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004934/* type id */ p->sys_ind,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004935/* type name */ partition_type(p->sys_ind));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004936 check_consistency(p, i);
4937 }
4938 }
4939
4940 /* Is partition table in disk order? It need not be, but... */
4941 /* partition table entries are not checked for correct order if this
4942 is a sgi, sun or aix labeled disk... */
4943 if (dos_label && wrong_p_order(NULL)) {
4944 printf(_("\nPartition table entries are not in disk order\n"));
4945 }
4946}
4947
4948#ifdef CONFIG_FEATURE_FDISK_ADVANCED
4949static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004950x_list_table(int extend)
4951{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004952 const struct pte *pe;
4953 const struct partition *p;
4954 int i;
4955
4956 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
4957 disk_device, heads, sectors, cylinders);
4958 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
4959 for (i = 0 ; i < partitions; i++) {
4960 pe = &ptes[i];
4961 p = (extend ? pe->ext_pointer : pe->part_table);
4962 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00004963 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004964 i + 1, p->boot_ind, p->head,
4965 sector(p->sector),
4966 cylinder(p->sector, p->cyl), p->end_head,
4967 sector(p->end_sector),
4968 cylinder(p->end_sector, p->end_cyl),
4969 get_start_sect(p), get_nr_sects(p), p->sys_ind);
4970 if (p->sys_ind)
4971 check_consistency(p, i);
4972 }
4973 }
4974}
4975#endif
4976
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00004977#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004978static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004979fill_bounds(off_t *first, off_t *last)
4980{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004981 int i;
4982 const struct pte *pe = &ptes[0];
4983 const struct partition *p;
4984
4985 for (i = 0; i < partitions; pe++,i++) {
4986 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00004987 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00004988 first[i] = 0xffffffff;
4989 last[i] = 0;
4990 } else {
4991 first[i] = get_partition_start(pe);
4992 last[i] = first[i] + get_nr_sects(p) - 1;
4993 }
4994 }
4995}
4996
4997static void
Rob Landleyb73451d2006-02-24 16:29:00 +00004998check(int n, uint h, uint s, uint c, off_t start)
4999{
Eric Andersend9261492004-06-28 23:50:31 +00005000 off_t total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005001
5002 real_s = sector(s) - 1;
5003 real_c = cylinder(s, c);
5004 total = (real_c * sectors + real_s) * heads + h;
5005 if (!total)
5006 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
5007 if (h >= heads)
5008 fprintf(stderr,
5009 _("Partition %d: head %d greater than maximum %d\n"),
5010 n, h + 1, heads);
5011 if (real_s >= sectors)
5012 fprintf(stderr, _("Partition %d: sector %d greater than "
5013 "maximum %d\n"), n, s, sectors);
5014 if (real_c >= cylinders)
Eric Andersend9261492004-06-28 23:50:31 +00005015 fprintf(stderr, _("Partitions %d: cylinder %llu greater than "
5016 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005017 if (cylinders <= 1024 && start != total)
5018 fprintf(stderr,
Eric Andersend9261492004-06-28 23:50:31 +00005019 _("Partition %d: previous sectors %llu disagrees with "
5020 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005021}
5022
5023static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005024verify(void)
5025{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005026 int i, j;
5027 uint total = 1;
Eric Andersend9261492004-06-28 23:50:31 +00005028 off_t first[partitions], last[partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005029 struct partition *p;
5030
5031 if (warn_geometry())
5032 return;
5033
5034#ifdef CONFIG_FEATURE_SUN_LABEL
5035 if (sun_label) {
5036 verify_sun();
5037 return;
5038 }
5039#endif
5040#ifdef CONFIG_FEATURE_SGI_LABEL
5041 if (sgi_label) {
5042 verify_sgi(1);
5043 return;
5044 }
5045#endif
5046
5047 fill_bounds(first, last);
5048 for (i = 0; i < partitions; i++) {
5049 struct pte *pe = &ptes[i];
5050
5051 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00005052 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005053 check_consistency(p, i);
5054 if (get_partition_start(pe) < first[i])
5055 printf(_("Warning: bad start-of-data in "
5056 "partition %d\n"), i + 1);
5057 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
5058 last[i]);
5059 total += last[i] + 1 - first[i];
5060 for (j = 0; j < i; j++)
5061 if ((first[i] >= first[j] && first[i] <= last[j])
5062 || ((last[i] <= last[j] && last[i] >= first[j]))) {
5063 printf(_("Warning: partition %d overlaps "
5064 "partition %d.\n"), j + 1, i + 1);
5065 total += first[i] >= first[j] ?
5066 first[i] : first[j];
5067 total -= last[i] <= last[j] ?
5068 last[i] : last[j];
5069 }
5070 }
5071 }
5072
5073 if (extended_offset) {
5074 struct pte *pex = &ptes[ext_index];
Eric Andersend9261492004-06-28 23:50:31 +00005075 off_t e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005076 get_nr_sects(pex->part_table) - 1;
5077
5078 for (i = 4; i < partitions; i++) {
5079 total++;
5080 p = ptes[i].part_table;
5081 if (!p->sys_ind) {
5082 if (i != 4 || i + 1 < partitions)
5083 printf(_("Warning: partition %d "
5084 "is empty\n"), i + 1);
5085 }
5086 else if (first[i] < extended_offset ||
5087 last[i] > e_last)
5088 printf(_("Logical partition %d not entirely in "
5089 "partition %d\n"), i + 1, ext_index + 1);
5090 }
5091 }
5092
5093 if (total > heads * sectors * cylinders)
5094 printf(_("Total allocated sectors %d greater than the maximum "
5095 "%d\n"), total, heads * sectors * cylinders);
5096 else if ((total = heads * sectors * cylinders - total) != 0)
5097 printf(_("%d unallocated sectors\n"), total);
5098}
5099
5100static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005101add_partition(int n, int sys)
5102{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005103 char mesg[256]; /* 48 does not suffice in Japanese */
5104 int i, readed = 0;
5105 struct partition *p = ptes[n].part_table;
5106 struct partition *q = ptes[ext_index].part_table;
Eric Andersen040f4402003-07-30 08:40:37 +00005107 long long llimit;
Eric Andersend9261492004-06-28 23:50:31 +00005108 off_t start, stop = 0, limit, temp,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005109 first[partitions], last[partitions];
5110
5111 if (p && p->sys_ind) {
5112 printf(_("Partition %d is already defined. Delete "
5113 "it before re-adding it.\n"), n + 1);
5114 return;
5115 }
5116 fill_bounds(first, last);
5117 if (n < 4) {
5118 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00005119 if (display_in_cyl_units || !total_number_of_sectors)
5120 llimit = heads * sectors * cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005121 else
Eric Andersen040f4402003-07-30 08:40:37 +00005122 llimit = total_number_of_sectors - 1;
5123 limit = llimit;
5124 if (limit != llimit)
5125 limit = 0x7fffffff;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005126 if (extended_offset) {
5127 first[ext_index] = extended_offset;
5128 last[ext_index] = get_start_sect(q) +
5129 get_nr_sects(q) - 1;
5130 }
5131 } else {
5132 start = extended_offset + sector_offset;
5133 limit = get_start_sect(q) + get_nr_sects(q) - 1;
5134 }
5135 if (display_in_cyl_units)
5136 for (i = 0; i < partitions; i++)
5137 first[i] = (cround(first[i]) - 1) * units_per_sector;
5138
5139 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
5140 do {
5141 temp = start;
5142 for (i = 0; i < partitions; i++) {
5143 int lastplusoff;
5144
5145 if (start == ptes[i].offset)
5146 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00005147 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005148 if (start >= first[i] && start <= lastplusoff)
5149 start = lastplusoff + 1;
5150 }
5151 if (start > limit)
5152 break;
5153 if (start >= temp+units_per_sector && readed) {
Eric Andersend9261492004-06-28 23:50:31 +00005154 printf(_("Sector %llu is already allocated\n"), (unsigned long long)temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005155 temp = start;
5156 readed = 0;
5157 }
5158 if (!readed && start == temp) {
Eric Andersend9261492004-06-28 23:50:31 +00005159 off_t saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005160
5161 saved_start = start;
5162 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
5163 0, mesg);
5164 if (display_in_cyl_units) {
5165 start = (start - 1) * units_per_sector;
5166 if (start < saved_start) start = saved_start;
5167 }
5168 readed = 1;
5169 }
5170 } while (start != temp || !readed);
5171 if (n > 4) { /* NOT for fifth partition */
5172 struct pte *pe = &ptes[n];
5173
5174 pe->offset = start - sector_offset;
5175 if (pe->offset == extended_offset) { /* must be corrected */
5176 pe->offset++;
5177 if (sector_offset == 1)
5178 start++;
5179 }
5180 }
5181
5182 for (i = 0; i < partitions; i++) {
5183 struct pte *pe = &ptes[i];
5184
5185 if (start < pe->offset && limit >= pe->offset)
5186 limit = pe->offset - 1;
5187 if (start < first[i] && limit >= first[i])
5188 limit = first[i] - 1;
5189 }
5190 if (start > limit) {
5191 printf(_("No free sectors available\n"));
5192 if (n > 4)
5193 partitions--;
5194 return;
5195 }
5196 if (cround(start) == cround(limit)) {
5197 stop = limit;
5198 } else {
5199 snprintf(mesg, sizeof(mesg),
5200 _("Last %s or +size or +sizeM or +sizeK"),
5201 str_units(SINGULAR));
5202 stop = read_int(cround(start), cround(limit), cround(limit),
5203 cround(start), mesg);
5204 if (display_in_cyl_units) {
5205 stop = stop * units_per_sector - 1;
5206 if (stop >limit)
5207 stop = limit;
5208 }
5209 }
5210
5211 set_partition(n, 0, start, stop, sys);
5212 if (n > 4)
5213 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
5214
Rob Landleyb73451d2006-02-24 16:29:00 +00005215 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005216 struct pte *pe4 = &ptes[4];
5217 struct pte *pen = &ptes[n];
5218
5219 ext_index = n;
5220 pen->ext_pointer = p;
5221 pe4->offset = extended_offset = start;
5222 pe4->sectorbuffer = xcalloc(1, sector_size);
5223 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
5224 pe4->ext_pointer = pe4->part_table + 1;
5225 pe4->changed = 1;
5226 partitions = 5;
5227 }
5228}
5229
5230static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005231add_logical(void)
5232{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005233 if (partitions > 5 || ptes[4].part_table->sys_ind) {
5234 struct pte *pe = &ptes[partitions];
5235
5236 pe->sectorbuffer = xcalloc(1, sector_size);
5237 pe->part_table = pt_offset(pe->sectorbuffer, 0);
5238 pe->ext_pointer = pe->part_table + 1;
5239 pe->offset = 0;
5240 pe->changed = 1;
5241 partitions++;
5242 }
5243 add_partition(partitions - 1, LINUX_NATIVE);
5244}
5245
5246static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005247new_partition(void)
5248{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005249 int i, free_primary = 0;
5250
5251 if (warn_geometry())
5252 return;
5253
5254#ifdef CONFIG_FEATURE_SUN_LABEL
5255 if (sun_label) {
5256 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5257 return;
5258 }
5259#endif
5260#ifdef CONFIG_FEATURE_SGI_LABEL
5261 if (sgi_label) {
5262 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
5263 return;
5264 }
5265#endif
5266#ifdef CONFIG_FEATURE_AIX_LABEL
5267 if (aix_label) {
5268 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
5269 "\n\tIf you want to add DOS-type partitions, create"
5270 "\n\ta new empty DOS partition table first. (Use o.)"
5271 "\n\tWARNING: "
5272 "This will destroy the present disk contents.\n"));
5273 return;
5274 }
5275#endif
5276
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005277 for (i = 0; i < 4; i++)
5278 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00005279
Rob Landleyb73451d2006-02-24 16:29:00 +00005280 if (!free_primary && partitions >= MAXIMUM_PARTS) {
Eric Andersen84bdea82004-05-19 10:49:17 +00005281 printf(_("The maximum number of partitions has been created\n"));
5282 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005283 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00005284
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005285 if (!free_primary) {
5286 if (extended_offset)
5287 add_logical();
5288 else
5289 printf(_("You must delete some partition and add "
5290 "an extended partition first\n"));
5291 } else {
5292 char c, line[LINE_LENGTH];
5293 snprintf(line, sizeof(line), "%s\n %s\n p primary "
5294 "partition (1-4)\n",
5295 "Command action", (extended_offset ?
5296 "l logical (5 or over)" : "e extended"));
5297 while (1) {
5298 if ((c = read_char(line)) == 'p' || c == 'P') {
5299 i = get_nonexisting_partition(0, 4);
5300 if (i >= 0)
5301 add_partition(i, LINUX_NATIVE);
5302 return;
5303 }
5304 else if (c == 'l' && extended_offset) {
5305 add_logical();
5306 return;
5307 }
5308 else if (c == 'e' && !extended_offset) {
5309 i = get_nonexisting_partition(0, 4);
5310 if (i >= 0)
5311 add_partition(i, EXTENDED);
5312 return;
5313 }
5314 else
5315 printf(_("Invalid partition number "
5316 "for type `%c'\n"), c);
5317 }
5318 }
5319}
5320
5321static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005322write_table(void)
5323{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005324 int i;
5325
5326 if (dos_label) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005327 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005328 if (ptes[i].changed)
5329 ptes[3].changed = 1;
5330 for (i = 3; i < partitions; i++) {
5331 struct pte *pe = &ptes[i];
5332
5333 if (pe->changed) {
5334 write_part_table_flag(pe->sectorbuffer);
5335 write_sector(pe->offset, pe->sectorbuffer);
5336 }
5337 }
5338 }
5339#ifdef CONFIG_FEATURE_SGI_LABEL
5340 else if (sgi_label) {
5341 /* no test on change? the printf below might be mistaken */
5342 sgi_write_table();
5343 }
5344#endif
5345#ifdef CONFIG_FEATURE_SUN_LABEL
Rob Landleyb73451d2006-02-24 16:29:00 +00005346 else if (sun_label) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005347 int needw = 0;
5348
Rob Landleyb73451d2006-02-24 16:29:00 +00005349 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005350 if (ptes[i].changed)
5351 needw = 1;
5352 if (needw)
5353 sun_write_table();
5354 }
5355#endif
5356
5357 printf(_("The partition table has been altered!\n\n"));
5358 reread_partition_table(1);
5359}
5360
Rob Landleyb73451d2006-02-24 16:29:00 +00005361static void
5362reread_partition_table(int leave)
5363{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005364 int error = 0;
5365 int i;
5366
5367 printf(_("Calling ioctl() to re-read partition table.\n"));
5368 sync();
5369 sleep(2);
5370 if ((i = ioctl(fd, BLKRRPART)) != 0) {
5371 error = errno;
5372 } else {
5373 /* some kernel versions (1.2.x) seem to have trouble
5374 rereading the partition table, but if asked to do it
5375 twice, the second time works. - biro@yggdrasil.com */
5376 sync();
5377 sleep(2);
5378 if ((i = ioctl(fd, BLKRRPART)) != 0)
5379 error = errno;
5380 }
5381
5382 if (i) {
5383 printf(_("\nWARNING: Re-reading the partition table "
5384 "failed with error %d: %s.\n"
5385 "The kernel still uses the old table.\n"
5386 "The new table will be used "
5387 "at the next reboot.\n"),
5388 error, strerror(error));
5389 }
5390
5391 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00005392 printf(
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005393 _("\nWARNING: If you have created or modified any DOS 6.x\n"
5394 "partitions, please see the fdisk manual page for additional\n"
5395 "information.\n"));
5396
5397 if (leave) {
5398 close(fd);
5399
5400 printf(_("Syncing disks.\n"));
5401 sync();
5402 sleep(4); /* for sync() */
5403 exit(!!i);
5404 }
5405}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005406#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005407
5408#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5409#define MAX_PER_LINE 16
5410static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005411print_buffer(char *pbuffer)
5412{
5413 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005414
5415 for (i = 0, l = 0; i < sector_size; i++, l++) {
5416 if (l == 0)
5417 printf("0x%03X:", i);
5418 printf(" %02X", (unsigned char) pbuffer[i]);
5419 if (l == MAX_PER_LINE - 1) {
5420 printf("\n");
5421 l = -1;
5422 }
5423 }
5424 if (l > 0)
5425 printf("\n");
5426 printf("\n");
5427}
5428
5429
5430static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005431print_raw(void)
5432{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005433 int i;
5434
5435 printf(_("Device: %s\n"), disk_device);
5436#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
5437 if (sun_label || sgi_label)
5438 print_buffer(MBRbuffer);
5439 else
5440#endif
5441 for (i = 3; i < partitions; i++)
5442 print_buffer(ptes[i].sectorbuffer);
5443}
5444
5445static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005446move_begin(int i)
5447{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005448 struct pte *pe = &ptes[i];
5449 struct partition *p = pe->part_table;
Eric Andersend9261492004-06-28 23:50:31 +00005450 off_t new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005451
5452 if (warn_geometry())
5453 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00005454 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005455 printf(_("Partition %d has no data area\n"), i + 1);
5456 return;
5457 }
5458 first = get_partition_start(pe);
5459 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Rob Landleyb73451d2006-02-24 16:29:00 +00005460 _("New beginning of data")) - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005461
5462 if (new != get_nr_sects(p)) {
5463 first = get_nr_sects(p) + get_start_sect(p) - new;
5464 set_nr_sects(p, first);
5465 set_start_sect(p, new);
5466 pe->changed = 1;
5467 }
5468}
5469
5470static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005471xselect(void)
5472{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005473 char c;
5474
Rob Landleyb73451d2006-02-24 16:29:00 +00005475 while (1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005476 putchar('\n');
5477 c = tolower(read_char(_("Expert command (m for help): ")));
5478 switch (c) {
5479 case 'a':
5480#ifdef CONFIG_FEATURE_SUN_LABEL
5481 if (sun_label)
5482 sun_set_alt_cyl();
5483#endif
5484 break;
5485 case 'b':
5486 if (dos_label)
5487 move_begin(get_partition(0, partitions));
5488 break;
5489 case 'c':
5490 user_cylinders = cylinders =
5491 read_int(1, cylinders, 1048576, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005492 _("Number of cylinders"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005493#ifdef CONFIG_FEATURE_SUN_LABEL
5494 if (sun_label)
5495 sun_set_ncyl(cylinders);
5496#endif
5497 if (dos_label)
5498 warn_cylinders();
5499 break;
5500 case 'd':
5501 print_raw();
5502 break;
5503 case 'e':
5504#ifdef CONFIG_FEATURE_SGI_LABEL
5505 if (sgi_label)
5506 sgi_set_xcyl();
5507 else
5508#endif
5509#ifdef CONFIG_FEATURE_SUN_LABEL
5510 if (sun_label)
5511 sun_set_xcyl();
5512 else
5513#endif
5514 if (dos_label)
5515 x_list_table(1);
5516 break;
5517 case 'f':
5518 if (dos_label)
5519 fix_partition_table_order();
5520 break;
5521 case 'g':
5522#ifdef CONFIG_FEATURE_SGI_LABEL
5523 create_sgilabel();
5524#endif
5525 break;
5526 case 'h':
5527 user_heads = heads = read_int(1, heads, 256, 0,
Rob Landleyb73451d2006-02-24 16:29:00 +00005528 _("Number of heads"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005529 update_units();
5530 break;
5531 case 'i':
5532#ifdef CONFIG_FEATURE_SUN_LABEL
5533 if (sun_label)
5534 sun_set_ilfact();
5535#endif
5536 break;
5537 case 'o':
5538#ifdef CONFIG_FEATURE_SUN_LABEL
5539 if (sun_label)
5540 sun_set_rspeed();
5541#endif
5542 break;
5543 case 'p':
5544#ifdef CONFIG_FEATURE_SUN_LABEL
5545 if (sun_label)
5546 list_table(1);
5547 else
5548#endif
5549 x_list_table(0);
5550 break;
5551 case 'q':
5552 close(fd);
5553 printf("\n");
5554 exit(0);
5555 case 'r':
5556 return;
5557 case 's':
5558 user_sectors = sectors = read_int(1, sectors, 63, 0,
5559 _("Number of sectors"));
5560 if (dos_compatible_flag) {
5561 sector_offset = sectors;
5562 fprintf(stderr, _("Warning: setting "
5563 "sector offset for DOS "
5564 "compatiblity\n"));
5565 }
5566 update_units();
5567 break;
5568 case 'v':
5569 verify();
5570 break;
5571 case 'w':
5572 write_table(); /* does not return */
5573 break;
5574 case 'y':
5575#ifdef CONFIG_FEATURE_SUN_LABEL
5576 if (sun_label)
5577 sun_set_pcylcount();
5578#endif
5579 break;
5580 default:
5581 xmenu();
5582 }
5583 }
5584}
5585#endif /* ADVANCED mode */
5586
5587static int
Rob Landleyb73451d2006-02-24 16:29:00 +00005588is_ide_cdrom_or_tape(const char *device)
5589{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005590 FILE *procf;
5591 char buf[100];
5592 struct stat statbuf;
5593 int is_ide = 0;
5594
5595 /* No device was given explicitly, and we are trying some
5596 likely things. But opening /dev/hdc may produce errors like
5597 "hdc: tray open or drive not ready"
5598 if it happens to be a CD-ROM drive. It even happens that
5599 the process hangs on the attempt to read a music CD.
5600 So try to be careful. This only works since 2.1.73. */
5601
5602 if (strncmp("/dev/hd", device, 7))
5603 return 0;
5604
5605 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
5606 procf = fopen(buf, "r");
5607 if (procf != NULL && fgets(buf, sizeof(buf), procf))
5608 is_ide = (!strncmp(buf, "cdrom", 5) ||
5609 !strncmp(buf, "tape", 4));
5610 else
5611 /* Now when this proc file does not exist, skip the
5612 device when it is read-only. */
5613 if (stat(device, &statbuf) == 0)
5614 is_ide = ((statbuf.st_mode & 0222) == 0);
5615
5616 if (procf)
5617 fclose(procf);
5618 return is_ide;
5619}
5620
5621static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005622try(const char *device, int user_specified)
5623{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005624 int gb;
5625
5626 disk_device = device;
5627 if (setjmp(listingbuf))
5628 return;
5629 if (!user_specified)
5630 if (is_ide_cdrom_or_tape(device))
5631 return;
5632 if ((fd = open(disk_device, type_open)) >= 0) {
5633 gb = get_boot(try_only);
5634 if (gb > 0) { /* I/O error */
5635 close(fd);
5636 } else if (gb < 0) { /* no DOS signature */
5637 list_disk_geometry();
5638 if (aix_label)
5639 return;
5640#ifdef CONFIG_FEATURE_OSF_LABEL
5641 if (btrydev(device) < 0)
5642#endif
5643 fprintf(stderr,
5644 _("Disk %s doesn't contain a valid "
Rob Landleyb73451d2006-02-24 16:29:00 +00005645 "partition table\n"), device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005646 close(fd);
5647 } else {
5648 close(fd);
5649 list_table(0);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005650#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005651 if (!sun_label && partitions > 4)
5652 delete_partition(ext_index);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005653#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005654 }
5655 } else {
5656 /* Ignore other errors, since we try IDE
5657 and SCSI hard disks which may not be
5658 installed on the system. */
5659 if (errno == EACCES) {
5660 fprintf(stderr, _("Cannot open %s\n"), device);
5661 return;
5662 }
5663 }
5664}
5665
5666/* for fdisk -l: try all things in /proc/partitions
5667 that look like a partition name (do not end in a digit) */
5668static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005669tryprocpt(void)
5670{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005671 FILE *procpt;
5672 char line[100], ptname[100], devname[120], *s;
5673 int ma, mi, sz;
5674
Manuel Novoa III cad53642003-03-19 09:13:01 +00005675 procpt = bb_wfopen(PROC_PARTITIONS, "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005676
5677 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00005678 if (sscanf(line, " %d %d %d %[^\n ]",
5679 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005680 continue;
5681 for (s = ptname; *s; s++);
5682 if (isdigit(s[-1]))
5683 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005684 sprintf(devname, "/dev/%s", ptname);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005685 try(devname, 0);
5686 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005687#ifdef CONFIG_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005688 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005689#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005690}
5691
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005692#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005693static void
Rob Landleyb73451d2006-02-24 16:29:00 +00005694unknown_command(int c)
5695{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005696 printf(_("%c: unknown command\n"), c);
5697}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005698#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005699
Rob Landleyb73451d2006-02-24 16:29:00 +00005700int fdisk_main(int argc, char **argv)
5701{
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005702 int c;
5703#ifdef CONFIG_FEATURE_FDISK_WRITABLE
5704 int optl = 0;
5705#endif
5706#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5707 int opts = 0;
5708#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005709 /*
5710 * Calls:
5711 * fdisk -v
5712 * fdisk -l [-b sectorsize] [-u] device ...
5713 * fdisk -s [partition] ...
5714 * fdisk [-b sectorsize] [-u] device
5715 *
5716 * Options -C, -H, -S set the geometry.
5717 *
5718 */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005719 while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
5720#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
5721 "s"
5722#endif
5723 )) != -1) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005724 switch (c) {
5725 case 'b':
5726 /* Ugly: this sector size is really per device,
5727 so cannot be combined with multiple disks,
5728 and te same goes for the C/H/S options.
5729 */
5730 sector_size = atoi(optarg);
5731 if (sector_size != 512 && sector_size != 1024 &&
Rob Landleyb73451d2006-02-24 16:29:00 +00005732 sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005733 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005734 sector_offset = 2;
5735 user_set_sector_size = 1;
5736 break;
5737 case 'C':
5738 user_cylinders = atoi(optarg);
5739 break;
5740 case 'H':
5741 user_heads = atoi(optarg);
5742 if (user_heads <= 0 || user_heads >= 256)
5743 user_heads = 0;
5744 break;
5745 case 'S':
5746 user_sectors = atoi(optarg);
5747 if (user_sectors <= 0 || user_sectors >= 64)
5748 user_sectors = 0;
5749 break;
5750 case 'l':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005751#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005752 optl = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005753#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005754 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005755#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005756 case 's':
5757 opts = 1;
5758 break;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005759#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005760 case 'u':
5761 display_in_cyl_units = 0;
5762 break;
5763 case 'V':
5764 case 'v':
5765 printf("fdisk v" UTIL_LINUX_VERSION "\n");
5766 return 0;
5767 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +00005768 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005769 }
5770 }
5771
5772#if 0
5773 printf(_("This kernel finds the sector size itself - "
5774 "-b option ignored\n"));
5775#else
5776 if (user_set_sector_size && argc-optind != 1)
5777 printf(_("Warning: the -b (set sector size) option should"
5778 " be used with one specified device\n"));
5779#endif
5780
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005781#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005782 if (optl) {
5783 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005784#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005785 type_open = O_RDONLY;
5786 if (argc > optind) {
5787 int k;
5788#if __GNUC__
5789 /* avoid gcc warning:
5790 variable `k' might be clobbered by `longjmp' */
5791 (void)&k;
5792#endif
5793 listing = 1;
Rob Landleyb73451d2006-02-24 16:29:00 +00005794 for (k = optind; k < argc; k++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005795 try(argv[k], 1);
5796 } else {
5797 /* we no longer have default device names */
5798 /* but, we can use /proc/partitions instead */
5799 tryprocpt();
5800 }
5801 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005802#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005803 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005804#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005805
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005806#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005807 if (opts) {
5808 long size;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005809 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005810
5811 nowarn = 1;
5812 type_open = O_RDONLY;
5813
5814 opts = argc - optind;
5815 if (opts <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00005816 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005817
5818 for (j = optind; j < argc; j++) {
5819 disk_device = argv[j];
5820 if ((fd = open(disk_device, type_open)) < 0)
5821 fdisk_fatal(unable_to_open);
5822 if (ioctl(fd, BLKGETSIZE, &size))
5823 fdisk_fatal(ioctl_error);
5824 close(fd);
5825 if (opts == 1)
5826 printf("%ld\n", size/2);
5827 else
5828 printf("%s: %ld\n", argv[j], size/2);
5829 }
5830 return 0;
5831 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005832#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005833
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005834#ifdef CONFIG_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005835 if (argc-optind == 1)
5836 disk_device = argv[optind];
5837 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00005838 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005839
5840 get_boot(fdisk);
5841
5842#ifdef CONFIG_FEATURE_OSF_LABEL
5843 if (osf_label) {
5844 /* OSF label, and no DOS label */
5845 printf(_("Detected an OSF/1 disklabel on %s, entering "
5846 "disklabel mode.\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005847 disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005848 bselect();
5849 osf_label = 0;
5850 /* If we return we may want to make an empty DOS label? */
5851 }
5852#endif
5853
5854 while (1) {
5855 putchar('\n');
5856 c = tolower(read_char(_("Command (m for help): ")));
5857 switch (c) {
5858 case 'a':
5859 if (dos_label)
5860 toggle_active(get_partition(1, partitions));
5861#ifdef CONFIG_FEATURE_SUN_LABEL
5862 else if (sun_label)
5863 toggle_sunflags(get_partition(1, partitions),
5864 0x01);
5865#endif
5866#ifdef CONFIG_FEATURE_SGI_LABEL
5867 else if (sgi_label)
5868 sgi_set_bootpartition(
5869 get_partition(1, partitions));
5870#endif
5871 else
5872 unknown_command(c);
5873 break;
5874 case 'b':
5875#ifdef CONFIG_FEATURE_SGI_LABEL
5876 if (sgi_label) {
5877 printf(_("\nThe current boot file is: %s\n"),
Rob Landleyb73451d2006-02-24 16:29:00 +00005878 sgi_get_bootfile());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005879 if (read_chars(_("Please enter the name of the "
Rob Landleyb73451d2006-02-24 16:29:00 +00005880 "new boot file: ")) == '\n')
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005881 printf(_("Boot file unchanged\n"));
5882 else
5883 sgi_set_bootfile(line_ptr);
5884 } else
5885#endif
5886#ifdef CONFIG_FEATURE_OSF_LABEL
5887 bselect();
5888#endif
5889 break;
5890 case 'c':
5891 if (dos_label)
5892 toggle_dos_compatibility_flag();
5893#ifdef CONFIG_FEATURE_SUN_LABEL
5894 else if (sun_label)
5895 toggle_sunflags(get_partition(1, partitions),
5896 0x10);
5897#endif
5898#ifdef CONFIG_FEATURE_SGI_LABEL
5899 else if (sgi_label)
5900 sgi_set_swappartition(
5901 get_partition(1, partitions));
5902#endif
5903 else
5904 unknown_command(c);
5905 break;
5906 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005907 {
Eric Andersen040f4402003-07-30 08:40:37 +00005908 int j;
5909#ifdef CONFIG_FEATURE_SGI_LABEL
5910 /* If sgi_label then don't use get_existing_partition,
5911 let the user select a partition, since
5912 get_existing_partition() only works for Linux-like
5913 partition tables */
5914 if (!sgi_label) {
5915 j = get_existing_partition(1, partitions);
5916 } else {
5917 j = get_partition(1, partitions);
5918 }
5919#else
5920 j = get_existing_partition(1, partitions);
5921#endif
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005922 if (j >= 0)
5923 delete_partition(j);
5924 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005925 break;
5926 case 'i':
5927#ifdef CONFIG_FEATURE_SGI_LABEL
5928 if (sgi_label)
5929 create_sgiinfo();
5930 else
5931#endif
5932 unknown_command(c);
5933 case 'l':
5934 list_types(get_sys_types());
5935 break;
5936 case 'm':
5937 menu();
5938 break;
5939 case 'n':
5940 new_partition();
5941 break;
5942 case 'o':
5943 create_doslabel();
5944 break;
5945 case 'p':
5946 list_table(0);
5947 break;
5948 case 'q':
5949 close(fd);
5950 printf("\n");
5951 return 0;
5952 case 's':
5953#ifdef CONFIG_FEATURE_SUN_LABEL
5954 create_sunlabel();
5955#endif
5956 break;
5957 case 't':
5958 change_sysid();
5959 break;
5960 case 'u':
5961 change_units();
5962 break;
5963 case 'v':
5964 verify();
5965 break;
5966 case 'w':
5967 write_table(); /* does not return */
5968 break;
5969#ifdef CONFIG_FEATURE_FDISK_ADVANCED
5970 case 'x':
5971#ifdef CONFIG_FEATURE_SGI_LABEL
5972 if (sgi_label) {
5973 fprintf(stderr,
5974 _("\n\tSorry, no experts menu for SGI "
5975 "partition tables available.\n\n"));
5976 } else
5977#endif
5978
5979 xselect();
5980 break;
5981#endif
5982 default:
5983 unknown_command(c);
5984 menu();
5985 }
5986 }
5987 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00005988#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00005989}