]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisk/fdisk.c
Imported from util-linux-2.11b tarball.
[thirdparty/util-linux.git] / fdisk / fdisk.c
CommitLineData
6dbe3af9
KZ
1/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
4 *
5 * This program is free software. You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation: either version 1 or
8 * (at your option) any later version.
9 *
22853e4a
KZ
10 * For detailed old history, see older versions.
11 * Contributions before 2000 by faith@cs.unc.edu, Michael Bischoff,
12 * LeBlanc@mcc.ac.uk, martin@cs.unc.edu, leisner@sdsp.mc.xerox.com,
13 * esr@snark.thyrsus.com, aeb@cwi.nl, quinlan@yggdrasil.com,
14 * fasten@cs.bonn.edu, orschaer@cip.informatik.uni-erlangen.de,
15 * jj@sunsite.mff.cuni.cz, fasten@shw.com, ANeuper@GUUG.de,
16 * kgw@suse.de.
7eda085c 17 *
22853e4a
KZ
18 * Modified, Sun Feb 20 2000, kalium@gmx.de
19 * Added fix operation allowing to reorder primary/extended partition
20 * entries within the partition table. Some programs or OSes have
21 * problems using a partition table with entries not ordered
22 * according to their positions on disk.
23 * Munged this patch to also make it work for logical partitions.
24 * aeb, 2000-02-20.
7eda085c 25 *
22853e4a
KZ
26 * Wed Mar 1 14:34:53 EST 2000 David Huggins-Daines <dhuggins@linuxcare.com>
27 * Better support for OSF/1 disklabels on Alpha.
7eda085c 28 *
22853e4a
KZ
29 * 2000-04-06, Michal Jaegermann (michal@ellpspace.math.ualberta.ca)
30 * fixed and added some alpha stuff.
6dbe3af9
KZ
31 */
32
33
34#include <unistd.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <fcntl.h>
39#include <ctype.h>
40#include <setjmp.h>
41#include <errno.h>
2b6fc908 42#include <getopt.h>
2b6fc908 43#include <sys/stat.h>
6dbe3af9 44
2b6fc908 45#include <linux/hdreg.h> /* for HDIO_GETGEO */
6dbe3af9 46
22853e4a 47#include "nls.h"
7eda085c 48#include "common.h"
726f69e2 49#include "fdisk.h"
5c36a0eb 50
2b6fc908 51#include "fdisksunlabel.h"
5c36a0eb
KZ
52#include "fdisksgilabel.h"
53#include "fdiskaixlabel.h"
54
7eda085c
KZ
55#include "../defines.h"
56#ifdef HAVE_blkpg_h
57#include <linux/blkpg.h>
58#endif
6dbe3af9 59
66ee8158
KZ
60static void delete_partition(int i);
61
6dbe3af9
KZ
62#define hex_val(c) ({ \
63 char _c = (c); \
64 isdigit(_c) ? _c - '0' : \
65 tolower(_c) + 10 - 'a'; \
66 })
67
68
c07ebfa1 69#define LINE_LENGTH 800
22853e4a 70#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
6dbe3af9
KZ
71 (n) * sizeof(struct partition)))
72#define sector(s) ((s) & 0x3f)
73#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
74
5c36a0eb 75#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
6dbe3af9
KZ
76 ((h) + heads * cylinder(s,c)))
77#define set_hsc(h,s,c,sector) { \
78 s = sector % sectors + 1; \
79 sector /= sectors; \
80 h = sector % heads; \
81 sector /= heads; \
82 c = sector & 0xff; \
83 s |= (sector >> 2) & 0xc0; \
84 }
85
2b6fc908 86/* A valid partition table sector ends in 0x55 0xaa */
22853e4a 87static unsigned int
2b6fc908
KZ
88part_table_flag(char *b) {
89 return ((uint) b[510]) + (((uint) b[511]) << 8);
90}
91
92int
93valid_part_table_flag(unsigned char *b) {
94 return (b[510] == 0x55 && b[511] == 0xaa);
95}
96
22853e4a 97static void
2b6fc908
KZ
98write_part_table_flag(char *b) {
99 b[510] = 0x55;
100 b[511] = 0xaa;
101}
102
103/* start_sect and nr_sects are stored little endian on all machines */
104/* moreover, they are not aligned correctly */
22853e4a 105static void
2b6fc908
KZ
106store4_little_endian(unsigned char *cp, unsigned int val) {
107 cp[0] = (val & 0xff);
108 cp[1] = ((val >> 8) & 0xff);
109 cp[2] = ((val >> 16) & 0xff);
110 cp[3] = ((val >> 24) & 0xff);
111}
112
22853e4a 113static unsigned int
2b6fc908
KZ
114read4_little_endian(unsigned char *cp) {
115 return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
116 + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
117}
118
22853e4a 119static void
2b6fc908
KZ
120set_start_sect(struct partition *p, unsigned int start_sect) {
121 store4_little_endian(p->start4, start_sect);
122}
123
124unsigned int
125get_start_sect(struct partition *p) {
126 return read4_little_endian(p->start4);
127}
128
22853e4a 129static void
2b6fc908
KZ
130set_nr_sects(struct partition *p, unsigned int nr_sects) {
131 store4_little_endian(p->size4, nr_sects);
132}
133
134unsigned int
135get_nr_sects(struct partition *p) {
136 return read4_little_endian(p->size4);
137}
138
726f69e2
KZ
139/* normally O_RDWR, -l option gives O_RDONLY */
140static int type_open = O_RDWR;
6dbe3af9 141
22853e4a
KZ
142/*
143 * Raw disk label. For DOS-type partition tables the MBR,
144 * with descriptions of the primary partitions.
145 */
146char MBRbuffer[MAX_SECTOR_SIZE];
147
148/*
149 * per partition table entry data
150 *
151 * The four primary partitions have the same sectorbuffer (MBRbuffer)
152 * and have NULL ext_pointer.
153 * Each logical partition table entry has two pointers, one for the
154 * partition and one link to the next one.
155 */
156struct pte {
157 struct partition *part_table; /* points into sectorbuffer */
158 struct partition *ext_pointer; /* points into sectorbuffer */
159 char changed; /* boolean */
160 uint offset; /* disk sector number */
161 char *sectorbuffer; /* disk sector contents */
162} ptes[MAXIMUM_PARTS];
163
7eda085c 164char *disk_device, /* must be specified */
6dbe3af9 165 *line_ptr, /* interactive input */
22853e4a 166 line_buffer[LINE_LENGTH];
6dbe3af9
KZ
167
168int fd, /* the disk */
169 ext_index, /* the prime extended partition */
170 listing = 0, /* no aborts for fdisk -l */
2b6fc908 171 nowarn = 0, /* no warnings for fdisk -l/-s */
6dbe3af9
KZ
172 dos_compatible_flag = ~0,
173 partitions = 4; /* maximum partition + 1 */
174
22853e4a
KZ
175uint user_cylinders, user_heads, user_sectors;
176
6dbe3af9
KZ
177uint heads,
178 sectors,
179 cylinders,
5c36a0eb 180 sector_size = DEFAULT_SECTOR_SIZE,
66ee8158 181 user_set_sector_size = 0,
6dbe3af9 182 sector_offset = 1,
7eda085c
KZ
183 units_per_sector = 1,
184 display_in_cyl_units = 1,
22853e4a 185 extended_offset = 0; /* offset of link pointers */
6dbe3af9 186
22853e4a 187#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
2b6fc908 188int sun_label = 0; /* looking at sun disklabel */
5c36a0eb
KZ
189int sgi_label = 0; /* looking at sgi disklabel */
190int aix_label = 0; /* looking at aix disklabel */
22853e4a 191int osf_label = 0; /* looking at osf disklabel */
6dbe3af9
KZ
192jmp_buf listingbuf;
193
22853e4a 194void fatal(enum failure why) {
6dbe3af9
KZ
195 char error[LINE_LENGTH],
196 *message = error;
197
198 if (listing) {
199 close(fd);
200 longjmp(listingbuf, 1);
201 }
202
203 switch (why) {
7eda085c
KZ
204 case usage: message = _(
205"Usage: fdisk [-b SSZ] [-u] DISK Change partition table\n"
206" fdisk -l [-b SSZ] [-u] DISK List partition table(s)\n"
207" fdisk -s PARTITION Give partition size(s) in blocks\n"
208" fdisk -v Give fdisk version\n"
5c36a0eb
KZ
209"Here DISK is something like /dev/hdb or /dev/sda\n"
210"and PARTITION is something like /dev/hda7\n"
211"-u: give Start and End in sector (instead of cylinder) units\n"
7eda085c
KZ
212"-b 2048: (for certain MO drives) use 2048-byte sectors\n");
213 break;
214 case usage2:
215 /* msg in cases where fdisk used to probe */
216 message = _(
217"Usage: fdisk [-l] [-b SSZ] [-u] device\n"
218"E.g.: fdisk /dev/hda (for the first IDE disk)\n"
219" or: fdisk /dev/sdc (for the third SCSI disk)\n"
220" or: fdisk /dev/eda (for the first PS/2 ESDI drive)\n"
221" or: fdisk /dev/rd/c0d0 or: fdisk /dev/ida/c0d0 (for RAID devices)\n"
222" ...\n");
5c36a0eb 223 break;
6dbe3af9 224 case unable_to_open:
c07ebfa1
KZ
225 snprintf(error, sizeof(error),
226 _("Unable to open %s\n"), disk_device);
6dbe3af9
KZ
227 break;
228 case unable_to_read:
c07ebfa1
KZ
229 snprintf(error, sizeof(error),
230 _("Unable to read %s\n"), disk_device);
6dbe3af9
KZ
231 break;
232 case unable_to_seek:
c07ebfa1
KZ
233 snprintf(error, sizeof(error),
234 _("Unable to seek on %s\n"),disk_device);
6dbe3af9
KZ
235 break;
236 case unable_to_write:
c07ebfa1
KZ
237 snprintf(error, sizeof(error),
238 _("Unable to write %s\n"), disk_device);
7eda085c
KZ
239 break;
240 case ioctl_error:
c07ebfa1
KZ
241 snprintf(error, sizeof(error),
242 _("BLKGETSIZE ioctl failed on %s\n"),
7eda085c 243 disk_device);
6dbe3af9
KZ
244 break;
245 case out_of_memory:
7eda085c 246 message = _("Unable to allocate any more memory\n");
6dbe3af9 247 break;
c07ebfa1
KZ
248 default:
249 message = _("Fatal error\n");
6dbe3af9
KZ
250 }
251
252 fputc('\n', stderr);
253 fputs(message, stderr);
254 exit(1);
255}
256
22853e4a
KZ
257static void
258seek_sector(int fd, uint secno) {
259 ext2_loff_t offset = (ext2_loff_t) secno * sector_size;
260 if (ext2_llseek(fd, offset, SEEK_SET) == (ext2_loff_t) -1)
261 fatal(unable_to_seek);
262}
263
264static void
265read_sector(int fd, uint secno, char *buf) {
266 seek_sector(fd, secno);
267 if (read(fd, buf, sector_size) != sector_size)
268 fatal(unable_to_read);
269}
270
271static void
272write_sector(int fd, uint secno, char *buf) {
273 seek_sector(fd, secno);
274 if (write(fd, buf, sector_size) != sector_size)
275 fatal(unable_to_write);
276}
277
278/* Allocate a buffer and read a partition table sector */
279static void
280read_pte(int fd, int pno, uint offset) {
281 struct pte *pe = &ptes[pno];
282
283 pe->offset = offset;
284 pe->sectorbuffer = (char *) malloc(sector_size);
285 if (!pe->sectorbuffer)
286 fatal(out_of_memory);
287 read_sector(fd, offset, pe->sectorbuffer);
288 pe->changed = 0;
289 pe->part_table = pe->ext_pointer = NULL;
290}
c07ebfa1 291
22853e4a
KZ
292static unsigned int
293get_partition_start(struct pte *pe) {
294 return pe->offset + get_start_sect(pe->part_table);
295}
296
297struct partition *
298get_part_table(int i) {
299 return ptes[i].part_table;
300}
301
302void
303set_all_unchanged(void) {
304 int i;
305
306 for (i = 0; i < MAXIMUM_PARTS; i++)
307 ptes[i].changed = 0;
308}
309
310void
311set_changed(int i) {
312 ptes[i].changed = 1;
313}
314
315static void
316menu(void) {
7eda085c
KZ
317 if (sun_label) {
318 puts(_("Command action"));
319 puts(_(" a toggle a read only flag")); /* sun */
320 puts(_(" b edit bsd disklabel"));
321 puts(_(" c toggle the mountable flag")); /* sun */
322 puts(_(" d delete a partition"));
323 puts(_(" l list known partition types"));
324 puts(_(" m print this menu"));
325 puts(_(" n add a new partition"));
326 puts(_(" o create a new empty DOS partition table"));
327 puts(_(" p print the partition table"));
328 puts(_(" q quit without saving changes"));
329 puts(_(" s create a new empty Sun disklabel")); /* sun */
330 puts(_(" t change a partition's system id"));
331 puts(_(" u change display/entry units"));
332 puts(_(" v verify the partition table"));
333 puts(_(" w write table to disk and exit"));
334 puts(_(" x extra functionality (experts only)"));
335 }
336 else if(sgi_label) {
337 puts(_("Command action"));
338 puts(_(" a select bootable partition")); /* sgi flavour */
339 puts(_(" b edit bootfile entry")); /* sgi */
340 puts(_(" c select sgi swap partition")); /* sgi flavour */
341 puts(_(" d delete a partition"));
342 puts(_(" l list known partition types"));
343 puts(_(" m print this menu"));
344 puts(_(" n add a new partition"));
345 puts(_(" o create a new empty DOS partition table"));
346 puts(_(" p print the partition table"));
347 puts(_(" q quit without saving changes"));
348 puts(_(" s create a new empty Sun disklabel")); /* sun */
349 puts(_(" t change a partition's system id"));
350 puts(_(" u change display/entry units"));
351 puts(_(" v verify the partition table"));
352 puts(_(" w write table to disk and exit"));
353 }
354 else if(aix_label) {
355 puts(_("Command action"));
356 puts(_(" m print this menu"));
357 puts(_(" o create a new empty DOS partition table"));
358 puts(_(" q quit without saving changes"));
359 puts(_(" s create a new empty Sun disklabel")); /* sun */
360 }
361 else {
362 puts(_("Command action"));
363 puts(_(" a toggle a bootable flag"));
364 puts(_(" b edit bsd disklabel"));
365 puts(_(" c toggle the dos compatibility flag"));
366 puts(_(" d delete a partition"));
367 puts(_(" l list known partition types"));
368 puts(_(" m print this menu"));
369 puts(_(" n add a new partition"));
370 puts(_(" o create a new empty DOS partition table"));
371 puts(_(" p print the partition table"));
372 puts(_(" q quit without saving changes"));
373 puts(_(" s create a new empty Sun disklabel")); /* sun */
374 puts(_(" t change a partition's system id"));
375 puts(_(" u change display/entry units"));
376 puts(_(" v verify the partition table"));
377 puts(_(" w write table to disk and exit"));
378 puts(_(" x extra functionality (experts only)"));
379 }
6dbe3af9
KZ
380}
381
22853e4a
KZ
382static void
383xmenu(void) {
7eda085c
KZ
384 if (sun_label) {
385 puts(_("Command action"));
22853e4a 386 puts(_(" a change number of alternate cylinders")); /*sun*/
7eda085c
KZ
387 puts(_(" c change number of cylinders"));
388 puts(_(" d print the raw data in the partition table"));
389 puts(_(" e change number of extra sectors per cylinder"));/*sun*/
390 puts(_(" h change number of heads"));
391 puts(_(" i change interleave factor")); /*sun*/
392 puts(_(" o change rotation speed (rpm)")); /*sun*/
393 puts(_(" m print this menu"));
394 puts(_(" p print the partition table"));
395 puts(_(" q quit without saving changes"));
396 puts(_(" r return to main menu"));
397 puts(_(" s change number of sectors/track"));
398 puts(_(" v verify the partition table"));
399 puts(_(" w write table to disk and exit"));
400 puts(_(" y change number of physical cylinders")); /*sun*/
401 }
22853e4a
KZ
402 else if(sgi_label) {
403 puts(_("Command action"));
404 puts(_(" b move beginning of data in a partition")); /* !sun */
405 puts(_(" c change number of cylinders"));
406 puts(_(" d print the raw data in the partition table"));
407 puts(_(" e list extended partitions")); /* !sun */
408 puts(_(" g create an IRIX partition table")); /* sgi */
409 puts(_(" h change number of heads"));
410 puts(_(" m print this menu"));
411 puts(_(" p print the partition table"));
412 puts(_(" q quit without saving changes"));
413 puts(_(" r return to main menu"));
414 puts(_(" s change number of sectors/track"));
415 puts(_(" v verify the partition table"));
416 puts(_(" w write table to disk and exit"));
417 }
418 else if(aix_label) {
419 puts(_("Command action"));
420 puts(_(" b move beginning of data in a partition")); /* !sun */
421 puts(_(" c change number of cylinders"));
422 puts(_(" d print the raw data in the partition table"));
423 puts(_(" e list extended partitions")); /* !sun */
424 puts(_(" g create an IRIX partition table")); /* sgi */
425 puts(_(" h change number of heads"));
426 puts(_(" m print this menu"));
427 puts(_(" p print the partition table"));
428 puts(_(" q quit without saving changes"));
429 puts(_(" r return to main menu"));
430 puts(_(" s change number of sectors/track"));
431 puts(_(" v verify the partition table"));
432 puts(_(" w write table to disk and exit"));
433 }
7eda085c
KZ
434 else {
435 puts(_("Command action"));
436 puts(_(" b move beginning of data in a partition")); /* !sun */
437 puts(_(" c change number of cylinders"));
438 puts(_(" d print the raw data in the partition table"));
439 puts(_(" e list extended partitions")); /* !sun */
22853e4a 440 puts(_(" f fix partition order")); /* !sun, !aix, !sgi */
7eda085c
KZ
441 puts(_(" g create an IRIX partition table")); /* sgi */
442 puts(_(" h change number of heads"));
443 puts(_(" m print this menu"));
444 puts(_(" p print the partition table"));
445 puts(_(" q quit without saving changes"));
446 puts(_(" r return to main menu"));
447 puts(_(" s change number of sectors/track"));
448 puts(_(" v verify the partition table"));
449 puts(_(" w write table to disk and exit"));
22853e4a 450 }
6dbe3af9
KZ
451}
452
22853e4a 453static int
5c36a0eb
KZ
454get_sysid(int i) {
455 return (
456 sun_label ? sunlabel->infos[i].id :
22853e4a 457 sgi_label ? sgi_get_sysid(i) : ptes[i].part_table->sys_ind);
5c36a0eb
KZ
458}
459
22853e4a 460static struct systypes *
5c36a0eb
KZ
461get_sys_types(void) {
462 return (
463 sun_label ? sun_sys_types :
7eda085c 464 sgi_label ? sgi_sys_types : i386_sys_types);
5c36a0eb
KZ
465}
466
6dbe3af9
KZ
467char *partition_type(unsigned char type)
468{
2b6fc908 469 int i;
5c36a0eb 470 struct systypes *types = get_sys_types();
2b6fc908
KZ
471
472 for (i=0; types[i].name; i++)
7eda085c
KZ
473 if (types[i].type == type)
474 return _(types[i].name);
2b6fc908 475
6dbe3af9
KZ
476 return NULL;
477}
478
2b6fc908 479void list_types(struct systypes *sys)
6dbe3af9 480{
2b6fc908 481 uint last[4], done = 0, next = 0, size;
6dbe3af9
KZ
482 int i;
483
2b6fc908
KZ
484 for (i = 0; sys[i].name; i++);
485 size = i;
486
6dbe3af9
KZ
487 for (i = 3; i >= 0; i--)
488 last[3 - i] = done += (size + i - done) / (i + 1);
489 i = done = 0;
490
491 do {
492 printf("%c%2x %-15.15s", i ? ' ' : '\n',
7eda085c 493 sys[next].type, _(sys[next].name));
726f69e2 494 next = last[i++] + done;
6dbe3af9
KZ
495 if (i > 3 || next >= last[i]) {
496 i = 0;
497 next = ++done;
498 }
499 } while (done < last[0]);
500 putchar('\n');
501}
502
22853e4a
KZ
503static void
504clear_partition(struct partition *p) {
505 if (!p)
506 return;
6dbe3af9
KZ
507 p->boot_ind = 0;
508 p->head = 0;
509 p->sector = 0;
510 p->cyl = 0;
511 p->sys_ind = 0;
512 p->end_head = 0;
513 p->end_sector = 0;
514 p->end_cyl = 0;
2b6fc908
KZ
515 set_start_sect(p,0);
516 set_nr_sects(p,0);
6dbe3af9
KZ
517}
518
22853e4a
KZ
519static void
520set_partition(int i, struct partition *p, uint start, uint stop,
521 int sysid, uint offset) {
6dbe3af9 522 p->boot_ind = 0;
2b6fc908
KZ
523 p->sys_ind = sysid;
524 set_start_sect(p, start - offset);
525 set_nr_sects(p, stop - start + 1);
6dbe3af9
KZ
526 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
527 start = heads*sectors*1024 - 1;
528 set_hsc(p->head, p->sector, p->cyl, start);
529 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
530 stop = heads*sectors*1024 - 1;
531 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
22853e4a 532 ptes[i].changed = 1;
6dbe3af9
KZ
533}
534
22853e4a
KZ
535static int
536test_c(char **m, char *mesg) {
6dbe3af9
KZ
537 int val = 0;
538 if (!*m)
7eda085c 539 fprintf(stderr, _("You must set"));
6dbe3af9
KZ
540 else {
541 fprintf(stderr, " %s", *m);
542 val = 1;
543 }
544 *m = mesg;
545 return val;
546}
547
22853e4a
KZ
548static int
549warn_geometry(void) {
6dbe3af9
KZ
550 char *m = NULL;
551 int prev = 0;
552 if (!heads)
7eda085c 553 prev = test_c(&m, _("heads"));
6dbe3af9 554 if (!sectors)
7eda085c 555 prev = test_c(&m, _("sectors"));
6dbe3af9 556 if (!cylinders)
7eda085c 557 prev = test_c(&m, _("cylinders"));
6dbe3af9
KZ
558 if (!m)
559 return 0;
560 fprintf(stderr,
7eda085c
KZ
561 _("%s%s.\nYou can do this from the extra functions menu.\n"),
562 prev ? _(" and ") : " ", m);
6dbe3af9
KZ
563 return 1;
564}
565
6dbe3af9
KZ
566void update_units(void)
567{
5c36a0eb
KZ
568 int cyl_units = heads * sectors;
569
7eda085c
KZ
570 if (display_in_cyl_units && cyl_units)
571 units_per_sector = cyl_units;
5c36a0eb 572 else
7eda085c 573 units_per_sector = 1; /* in sectors */
6dbe3af9
KZ
574}
575
22853e4a
KZ
576static void
577warn_cylinders(void) {
578 if (dos_label && cylinders > 1024 && !nowarn)
66ee8158
KZ
579 fprintf(stderr, _("\n"
580"The number of cylinders for this disk is set to %d.\n"
581"There is nothing wrong with that, but this is larger than 1024,\n"
582"and could in certain setups cause problems with:\n"
583"1) software that runs at boot time (e.g., old versions of LILO)\n"
584"2) booting and partitioning software from other OSs\n"
585" (e.g., DOS FDISK, OS/2 FDISK)\n"),
6dbe3af9
KZ
586 cylinders);
587}
588
22853e4a
KZ
589static void
590read_extended(int ext) {
6dbe3af9 591 int i;
22853e4a
KZ
592 struct pte *pex;
593 struct partition *p, *q;
594
595 ext_index = ext;
596 pex = &ptes[ext];
597 pex->ext_pointer = pex->part_table;
6dbe3af9 598
22853e4a 599 p = pex->part_table;
66ee8158
KZ
600 if (!get_start_sect(p)) {
601 fprintf(stderr,
602 _("Bad offset in primary extended partition\n"));
603 return;
604 }
605
606 while (IS_EXTENDED (p->sys_ind)) {
22853e4a
KZ
607 struct pte *pe = &ptes[partitions];
608
6dbe3af9 609 if (partitions >= MAXIMUM_PARTS) {
7eda085c
KZ
610 /* This is not a Linux restriction, but
611 this program uses arrays of size MAXIMUM_PARTS.
612 Do not try to `improve' this test. */
22853e4a
KZ
613 struct pte *pre = &ptes[partitions-1];
614
6dbe3af9 615 fprintf(stderr,
7eda085c 616 _("Warning: deleting partitions after %d\n"),
6dbe3af9 617 partitions);
22853e4a
KZ
618 clear_partition(pre->ext_pointer);
619 pre->changed = 1;
6dbe3af9
KZ
620 return;
621 }
22853e4a
KZ
622
623 read_pte(fd, partitions, extended_offset + get_start_sect(p));
624
6dbe3af9 625 if (!extended_offset)
2b6fc908 626 extended_offset = get_start_sect(p);
22853e4a
KZ
627
628 q = p = pt_offset(pe->sectorbuffer, 0);
66ee8158 629 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
5c36a0eb 630 if (IS_EXTENDED (p->sys_ind)) {
22853e4a 631 if (pe->ext_pointer)
c07ebfa1
KZ
632 fprintf(stderr,
633 _("Warning: extra link "
634 "pointer in partition table"
635 " %d\n"), partitions + 1);
6dbe3af9 636 else
22853e4a 637 pe->ext_pointer = p;
5c36a0eb 638 } else if (p->sys_ind) {
22853e4a 639 if (pe->part_table)
6dbe3af9 640 fprintf(stderr,
c07ebfa1
KZ
641 _("Warning: ignoring extra "
642 "data in partition table"
643 " %d\n"), partitions + 1);
6dbe3af9 644 else
22853e4a 645 pe->part_table = p;
5c36a0eb 646 }
6dbe3af9 647 }
22853e4a
KZ
648
649 /* very strange code here... */
650 if (!pe->part_table) {
651 if (q != pe->ext_pointer)
652 pe->part_table = q;
653 else
654 pe->part_table = q + 1;
5c36a0eb 655 }
22853e4a
KZ
656 if (!pe->ext_pointer) {
657 if (q != pe->part_table)
658 pe->ext_pointer = q;
659 else
660 pe->ext_pointer = q + 1;
5c36a0eb 661 }
22853e4a
KZ
662
663 p = pe->ext_pointer;
664 partitions++;
6dbe3af9 665 }
66ee8158
KZ
666
667 /* remove empty links */
668 remove:
669 for (i = 4; i < partitions; i++) {
670 struct pte *pe = &ptes[i];
671
c07ebfa1
KZ
672 if (!get_nr_sects(pe->part_table) &&
673 (partitions > 5 || ptes[4].part_table->sys_ind)) {
66ee8158
KZ
674 printf("omitting empty partition (%d)\n", i+1);
675 delete_partition(i);
676 goto remove; /* numbering changed */
677 }
678 }
6dbe3af9
KZ
679}
680
22853e4a
KZ
681static void
682create_doslabel(void) {
2b6fc908
KZ
683 int i;
684
685 fprintf(stderr,
7eda085c
KZ
686 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
687 "until you decide to write them. After that, of course, the previous\n"
688 "content won't be recoverable.\n\n"));
2b6fc908 689
5c36a0eb
KZ
690 sun_nolabel(); /* otherwise always recognised as sun */
691 sgi_nolabel(); /* otherwise always recognised as sgi */
692
c07ebfa1
KZ
693 for (i = 510-64; i < 510; i++)
694 MBRbuffer[i] = 0;
22853e4a 695 write_part_table_flag(MBRbuffer);
c07ebfa1 696 extended_offset = 0;
22853e4a
KZ
697 set_all_unchanged();
698 set_changed(0);
2b6fc908
KZ
699 get_boot(create_empty);
700}
701
66ee8158
KZ
702#include <sys/utsname.h>
703#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
704
705static int
706linux_version_code(void) {
707 static int kernel_version = 0;
708 struct utsname my_utsname;
709 int p, q, r;
710
711 if (!kernel_version && uname(&my_utsname) == 0) {
712 p = atoi(strtok(my_utsname.release, "."));
713 q = atoi(strtok(NULL, "."));
714 r = atoi(strtok(NULL, "."));
715 kernel_version = MAKE_VERSION(p,q,r);
716 }
717 return kernel_version;
718}
719
22853e4a
KZ
720static void
721get_sectorsize(int fd) {
66ee8158
KZ
722#if defined(BLKSSZGET)
723 if (!user_set_sector_size &&
724 linux_version_code() >= MAKE_VERSION(2,3,3)) {
725 int arg;
726 if (ioctl(fd, BLKSSZGET, &arg) == 0)
727 sector_size = arg;
728 if (sector_size != DEFAULT_SECTOR_SIZE)
729 printf(_("Note: sector size is %d (not %d)\n"),
730 sector_size, DEFAULT_SECTOR_SIZE);
7eda085c 731 }
22853e4a 732#else
66ee8158
KZ
733 /* maybe the user specified it; and otherwise we still
734 have the DEFAULT_SECTOR_SIZE default */
7eda085c 735#endif
22853e4a 736}
7eda085c 737
22853e4a
KZ
738/*
739 * Ask kernel about geometry. Invent something reasonable
740 * in case the kernel has no opinion.
741 */
742void
743get_geometry(int fd, struct geom *g) {
744 int sec_fac;
745 long longsectors;
746 struct hd_geometry geometry;
747 int res1, res2;
2b6fc908 748
22853e4a
KZ
749 get_sectorsize(fd);
750 sec_fac = sector_size / 512;
fd6b7a7f 751
22853e4a
KZ
752 guess_device_type(fd);
753
754 res1 = ioctl(fd, BLKGETSIZE, &longsectors);
726f69e2 755#ifdef HDIO_REQ
22853e4a 756 res2 = ioctl(fd, HDIO_REQ, &geometry);
726f69e2 757#else
22853e4a 758 res2 = ioctl(fd, HDIO_GETGEO, &geometry);
726f69e2 759#endif
22853e4a
KZ
760
761 /* never use geometry.cylinders - it is truncated */
762 heads = cylinders = sectors = 0;
763 sector_offset = 1;
764 if (res2 == 0) {
6dbe3af9
KZ
765 heads = geometry.heads;
766 sectors = geometry.sectors;
22853e4a
KZ
767 if (heads * sectors == 0)
768 res2 = -1;
769 else if (dos_compatible_flag)
6dbe3af9 770 sector_offset = sectors;
6dbe3af9 771 }
22853e4a
KZ
772 if (res1 == 0 && res2 == 0) { /* normal case */
773 cylinders = longsectors / (heads * sectors);
774 cylinders /= sec_fac; /* do not round up */
775 } else if (res1 == 0) { /* size but no geometry */
776 heads = cylinders = 1;
777 sectors = longsectors / sec_fac;
778 }
779
780 if (!sectors)
781 sectors = user_sectors;
782 if (!heads)
783 heads = user_heads;
784 if (!cylinders)
785 cylinders = user_cylinders;
786
787 if (g) {
788 g->heads = heads;
789 g->sectors = sectors;
790 g->cylinders = cylinders;
791 }
792}
793
794/*
795 * Read MBR. Returns:
796 * -1: no 0xaa55 flag present (possibly entire disk BSD)
797 * 0: found or created label
798 */
799int
800get_boot(enum action what) {
801 int i;
802
803 partitions = 4;
804
805 if (what == create_empty)
806 goto got_table; /* skip reading disk */
807
808 if ((fd = open(disk_device, type_open)) < 0) {
809 if ((fd = open(disk_device, O_RDONLY)) < 0)
810 fatal(unable_to_open);
811 else
812 printf(_("You will not be able to write the partition table.\n"));
813 }
814
815 get_geometry(fd, NULL);
816
2b6fc908
KZ
817 update_units();
818
22853e4a
KZ
819 if (sector_size != read(fd, MBRbuffer, sector_size))
820 fatal(unable_to_read);
821
2b6fc908 822got_table:
6dbe3af9 823
2b6fc908
KZ
824 if (check_sun_label())
825 return 0;
5c36a0eb
KZ
826
827 if (check_sgi_label())
828 return 0;
829
830 if (check_aix_label())
831 return 0;
2b6fc908 832
22853e4a
KZ
833 if (check_osf_label())
834 return 0;
835
836 if (!valid_part_table_flag(MBRbuffer)) {
2b6fc908
KZ
837 switch(what) {
838 case fdisk:
839 fprintf(stderr,
7eda085c 840 _("Device contains neither a valid DOS partition"
22853e4a 841 " table, nor Sun, SGI or OSF disklabel\n"));
2b6fc908
KZ
842#ifdef __sparc__
843 create_sunlabel();
844#else
845 create_doslabel();
846#endif
847 return 0;
848 case require:
849 return -1;
850 case try_only:
851 return -1;
852 case create_empty:
853 break;
854 }
855
7eda085c 856 fprintf(stderr, _("Internal error\n"));
2b6fc908 857 exit(1);
fd6b7a7f
KZ
858 }
859
2b6fc908
KZ
860 warn_cylinders();
861 warn_geometry();
862
22853e4a
KZ
863 for (i = 0; i < 4; i++) {
864 struct pte *pe = &ptes[i];
865
866 pe->part_table = pt_offset(MBRbuffer, i);
867 pe->ext_pointer = NULL;
22853e4a
KZ
868 pe->offset = 0;
869 pe->sectorbuffer = MBRbuffer;
66ee8158 870 pe->changed = (what == create_empty);
22853e4a
KZ
871 }
872
873 for (i = 0; i < 4; i++) {
874 struct pte *pe = &ptes[i];
875
876 if (IS_EXTENDED (pe->part_table->sys_ind)) {
6dbe3af9 877 if (partitions != 4)
7eda085c
KZ
878 fprintf(stderr, _("Ignoring extra extended "
879 "partition %d\n"), i + 1);
22853e4a
KZ
880 else
881 read_extended(i);
5c36a0eb 882 }
22853e4a
KZ
883 }
884
885 for (i = 3; i < partitions; i++) {
886 struct pte *pe = &ptes[i];
887
888 if (!valid_part_table_flag(pe->sectorbuffer)) {
2b6fc908 889 fprintf(stderr,
7eda085c
KZ
890 _("Warning: invalid flag 0x%04x of partition "
891 "table %d will be corrected by w(rite)\n"),
22853e4a
KZ
892 part_table_flag(pe->sectorbuffer), i + 1);
893 pe->changed = 1;
6dbe3af9 894 }
22853e4a 895 }
fd6b7a7f 896
2b6fc908 897 return 0;
6dbe3af9
KZ
898}
899
5c36a0eb
KZ
900/* read line; return 0 or first char */
901int
902read_line(void)
6dbe3af9 903{
7eda085c
KZ
904 static int got_eof = 0;
905
5c36a0eb 906 line_ptr = line_buffer;
7eda085c
KZ
907 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
908 if (feof(stdin))
909 got_eof++; /* user typed ^D ? */
910 if (got_eof >= 3) {
911 fflush(stdout);
912 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
913 exit(1);
914 }
6dbe3af9 915 return 0;
7eda085c 916 }
6dbe3af9
KZ
917 while (*line_ptr && !isgraph(*line_ptr))
918 line_ptr++;
919 return *line_ptr;
920}
921
5c36a0eb
KZ
922char
923read_char(char *mesg)
6dbe3af9 924{
2b6fc908 925 do {
6dbe3af9 926 fputs(mesg, stdout);
66ee8158 927 fflush (stdout); /* requested by niles@scyld.com */
2b6fc908 928 } while (!read_line());
6dbe3af9
KZ
929 return *line_ptr;
930}
931
5c36a0eb
KZ
932char
933read_chars(char *mesg)
2b6fc908
KZ
934{
935 fputs(mesg, stdout);
66ee8158 936 fflush (stdout); /* niles@scyld.com */
2b6fc908
KZ
937 if (!read_line()) {
938 *line_ptr = '\n';
5c36a0eb
KZ
939 line_ptr[1] = 0;
940 }
941 return *line_ptr;
2b6fc908
KZ
942}
943
5c36a0eb
KZ
944int
945read_hex(struct systypes *sys)
6dbe3af9 946{
726f69e2
KZ
947 int hex;
948
949 while (1)
950 {
7eda085c 951 read_char(_("Hex code (type L to list codes): "));
726f69e2 952 if (tolower(*line_ptr) == 'l')
2b6fc908 953 list_types(sys);
726f69e2
KZ
954 else if (isxdigit (*line_ptr))
955 {
956 hex = 0;
957 do
958 hex = hex << 4 | hex_val(*line_ptr++);
959 while (isxdigit(*line_ptr));
960 return hex;
961 }
962 }
963}
964
5c36a0eb 965/*
eb63b9b8 966 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
5c36a0eb
KZ
967 * If the user hits Enter, DFLT is returned.
968 * Answers like +10 are interpreted as offsets from BASE.
969 *
970 * There is no default if DFLT is not between LOW and HIGH.
971 */
972uint
973read_int(uint low, uint dflt, uint high, uint base, char *mesg)
726f69e2 974{
5c36a0eb
KZ
975 uint i;
976 int default_ok = 1;
977 static char *ms = NULL;
978 static int mslen = 0;
979
c07ebfa1
KZ
980 if (!ms || strlen(mesg)+100 > mslen) {
981 mslen = strlen(mesg)+200;
5c36a0eb
KZ
982 if (!(ms = realloc(ms,mslen)))
983 fatal(out_of_memory);
726f69e2 984 }
6dbe3af9 985
5c36a0eb
KZ
986 if (dflt < low || dflt > high)
987 default_ok = 0;
988
989 if (default_ok)
c07ebfa1
KZ
990 snprintf(ms, mslen, _("%s (%d-%d, default %d): "),
991 mesg, low, high, dflt);
5c36a0eb 992 else
c07ebfa1
KZ
993 snprintf(ms, mslen, "%s (%d-%d): ",
994 mesg, low, high);
5c36a0eb 995
6dbe3af9 996 while (1) {
5c36a0eb
KZ
997 int use_default = default_ok;
998
999 /* ask question and read answer */
1000 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
1001 && *line_ptr != '-' && *line_ptr != '+')
1002 continue;
1003
726f69e2 1004 if (*line_ptr == '+' || *line_ptr == '-') {
5c36a0eb
KZ
1005 i = atoi(line_ptr+1);
1006 if (*line_ptr == '-')
1007 i = -i;
1008 while (isdigit(*++line_ptr))
726f69e2 1009 use_default = 0;
6dbe3af9
KZ
1010 switch (*line_ptr) {
1011 case 'c':
5c36a0eb 1012 case 'C':
7eda085c 1013 if (!display_in_cyl_units)
6dbe3af9
KZ
1014 i *= heads * sectors;
1015 break;
1016 case 'k':
5c36a0eb
KZ
1017 case 'K':
1018 i *= 2;
1019 i /= (sector_size / 512);
7eda085c 1020 i /= units_per_sector;
6dbe3af9
KZ
1021 break;
1022 case 'm':
5c36a0eb
KZ
1023 case 'M':
1024 i *= 2048;
1025 i /= (sector_size / 512);
7eda085c 1026 i /= units_per_sector;
6dbe3af9 1027 break;
5c36a0eb
KZ
1028 case 'g':
1029 case 'G':
1030 i *= 2048000;
1031 i /= (sector_size / 512);
7eda085c 1032 i /= units_per_sector;
5c36a0eb
KZ
1033 break;
1034 default:
1035 break;
726f69e2 1036 }
5c36a0eb
KZ
1037 i += base;
1038 } else {
726f69e2 1039 i = atoi(line_ptr);
5c36a0eb 1040 while (isdigit(*line_ptr)) {
726f69e2
KZ
1041 line_ptr++;
1042 use_default = 0;
1043 }
1044 }
1045 if (use_default)
22853e4a 1046 printf(_("Using default value %d\n"), i = dflt);
6dbe3af9
KZ
1047 if (i >= low && i <= high)
1048 break;
726f69e2 1049 else
7eda085c 1050 printf(_("Value out of range.\n"));
6dbe3af9 1051 }
6dbe3af9
KZ
1052 return i;
1053}
1054
22853e4a
KZ
1055int
1056get_partition(int warn, int max) {
1057 struct pte *pe;
1058 int i;
1059
1060 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
1061 pe = &ptes[i];
6dbe3af9 1062
2b6fc908 1063 if (warn && (
22853e4a 1064 (!sun_label && !sgi_label && !pe->part_table->sys_ind)
2b6fc908
KZ
1065 || (sun_label &&
1066 (!sunlabel->partitions[i].num_sectors ||
1067 !sunlabel->infos[i].id))
5c36a0eb 1068 || (sgi_label && (!sgi_get_num_sectors(i)))
7eda085c 1069 )) fprintf(stderr, _("Warning: partition %d has empty type\n"), i+1);
6dbe3af9
KZ
1070 return i;
1071}
1072
22853e4a
KZ
1073char * const
1074str_units(int n) { /* n==1: use singular */
7eda085c
KZ
1075 if (n == 1)
1076 return display_in_cyl_units ? _("cylinder") : _("sector");
1077 else
1078 return display_in_cyl_units ? _("cylinders") : _("sectors");
6dbe3af9
KZ
1079}
1080
1081void change_units(void)
1082{
7eda085c 1083 display_in_cyl_units = !display_in_cyl_units;
6dbe3af9 1084 update_units();
7eda085c
KZ
1085 printf(_("Changing display/entry units to %s\n"),
1086 str_units(PLURAL));
6dbe3af9
KZ
1087}
1088
22853e4a
KZ
1089static void
1090toggle_active(int i) {
1091 struct pte *pe = &ptes[i];
1092 struct partition *p = pe->part_table;
6dbe3af9 1093
2b6fc908 1094 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
6dbe3af9 1095 fprintf(stderr,
7eda085c 1096 _("WARNING: Partition %d is an extended partition\n"),
6dbe3af9 1097 i + 1);
22853e4a
KZ
1098 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1099 pe->changed = 1;
6dbe3af9
KZ
1100}
1101
22853e4a
KZ
1102static void
1103toggle_dos_compatibility_flag(void) {
6dbe3af9 1104 dos_compatible_flag = ~dos_compatible_flag;
7eda085c 1105 if (dos_compatible_flag) {
6dbe3af9 1106 sector_offset = sectors;
7eda085c
KZ
1107 printf(_("DOS Compatibility flag is set\n"));
1108 }
6dbe3af9
KZ
1109 else {
1110 sector_offset = 1;
7eda085c 1111 printf(_("DOS Compatibility flag is not set\n"));
6dbe3af9 1112 }
6dbe3af9
KZ
1113}
1114
22853e4a
KZ
1115static void
1116delete_partition(int i) {
1117 struct pte *pe = &ptes[i];
1118 struct partition *p = pe->part_table;
1119 struct partition *q = pe->ext_pointer;
6dbe3af9
KZ
1120
1121/* Note that for the fifth partition (i == 4) we don't actually
1122 * decrement partitions.
1123 */
1124
1125 if (warn_geometry())
1126 return;
22853e4a 1127 pe->changed = 1;
5c36a0eb 1128
2b6fc908
KZ
1129 if (sun_label) {
1130 sun_delete_partition(i);
1131 return;
1132 }
66ee8158 1133
5c36a0eb
KZ
1134 if (sgi_label) {
1135 sgi_delete_partition(i);
1136 return;
1137 }
66ee8158 1138
6dbe3af9 1139 if (i < 4) {
2b6fc908 1140 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
22853e4a
KZ
1141 partitions = 4;
1142 ptes[ext_index].ext_pointer = NULL;
6dbe3af9
KZ
1143 extended_offset = 0;
1144 }
1145 clear_partition(p);
66ee8158 1146 return;
6dbe3af9 1147 }
66ee8158
KZ
1148
1149 if (!q->sys_ind && i > 4) {
c07ebfa1 1150 /* the last one in the chain - just delete */
22853e4a
KZ
1151 --partitions;
1152 --i;
1153 clear_partition(ptes[i].ext_pointer);
1154 ptes[i].changed = 1;
66ee8158 1155 } else {
c07ebfa1 1156 /* not the last one - further ones will be moved down */
6dbe3af9 1157 if (i > 4) {
c07ebfa1 1158 /* delete this link in the chain */
22853e4a 1159 p = ptes[i-1].ext_pointer;
6dbe3af9
KZ
1160 p->boot_ind = 0;
1161 p->head = q->head;
1162 p->sector = q->sector;
1163 p->cyl = q->cyl;
1164 p->sys_ind = EXTENDED;
1165 p->end_head = q->end_head;
1166 p->end_sector = q->end_sector;
1167 p->end_cyl = q->end_cyl;
2b6fc908
KZ
1168 set_start_sect(p, get_start_sect(q));
1169 set_nr_sects(p, get_nr_sects(q));
22853e4a 1170 ptes[i-1].changed = 1;
66ee8158 1171 } else if (partitions > 5) { /* 5 will be moved to 4 */
c07ebfa1 1172 /* the first logical in a longer chain */
22853e4a
KZ
1173 struct pte *pe = &ptes[5];
1174
1175 if(pe->part_table) /* prevent SEGFAULT */
1176 set_start_sect(pe->part_table,
1177 get_partition_start(pe) -
1178 extended_offset);
1179 pe->offset = extended_offset;
1180 pe->changed = 1;
6dbe3af9 1181 }
66ee8158 1182
6dbe3af9
KZ
1183 if (partitions > 5) {
1184 partitions--;
6dbe3af9 1185 while (i < partitions) {
22853e4a 1186 ptes[i] = ptes[i+1];
6dbe3af9
KZ
1187 i++;
1188 }
22853e4a 1189 } else
c07ebfa1 1190 /* the only logical: clear only */
22853e4a 1191 clear_partition(ptes[i].part_table);
6dbe3af9
KZ
1192 }
1193}
1194
22853e4a
KZ
1195static void
1196change_sysid(void) {
6dbe3af9 1197 char *temp;
2b6fc908 1198 int i = get_partition(0, partitions), sys, origsys;
22853e4a 1199 struct partition *p = ptes[i].part_table;
6dbe3af9 1200
5c36a0eb 1201 origsys = sys = get_sysid(i);
2b6fc908 1202
c07ebfa1 1203 if (!sys && !sgi_label && !sun_label)
7eda085c 1204 printf(_("Partition %d does not exist yet!\n"), i + 1);
2b6fc908 1205 else while (1) {
5c36a0eb
KZ
1206 sys = read_hex (get_sys_types());
1207
c07ebfa1 1208 if (!sys && !sgi_label && !sun_label) {
7eda085c 1209 printf(_("Type 0 means free space to many systems\n"
5c36a0eb
KZ
1210 "(but not to Linux). Having partitions of\n"
1211 "type 0 is probably unwise. You can delete\n"
7eda085c 1212 "a partition using the `d' command.\n"));
5c36a0eb 1213 /* break; */
2b6fc908
KZ
1214 }
1215
5c36a0eb 1216 if (!sun_label && !sgi_label) {
2b6fc908 1217 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
7eda085c 1218 printf(_("You cannot change a partition into"
2b6fc908 1219 " an extended one or vice versa\n"
7eda085c 1220 "Delete it first.\n"));
6dbe3af9
KZ
1221 break;
1222 }
1223 }
2b6fc908
KZ
1224
1225 if (sys < 256) {
2b6fc908 1226 if (sun_label && i == 2 && sys != WHOLE_DISK)
7eda085c 1227 printf(_("Consider leaving partition 3 "
2b6fc908
KZ
1228 "as Whole disk (5),\n"
1229 "as SunOS/Solaris expects it and "
7eda085c 1230 "even Linux likes it.\n\n"));
5c36a0eb
KZ
1231 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
1232 || (i == 8 && sys != 0)))
7eda085c 1233 printf(_("Consider leaving partition 9 "
5c36a0eb
KZ
1234 "as volume header (0),\nand "
1235 "partition 11 as entire volume (6)"
7eda085c 1236 "as IRIX expects it.\n\n"));
2b6fc908
KZ
1237 if (sys == origsys)
1238 break;
5c36a0eb
KZ
1239
1240 if (sun_label) {
2b6fc908
KZ
1241 sun_change_sysid(i, sys);
1242 } else
5c36a0eb
KZ
1243 if (sgi_label) {
1244 sgi_change_sysid(i, sys);
1245 } else
22853e4a 1246 p->sys_ind = sys;
7eda085c
KZ
1247 printf (_("Changed system type of partition %d "
1248 "to %x (%s)\n"), i + 1, sys,
2b6fc908 1249 (temp = partition_type(sys)) ? temp :
7eda085c 1250 _("Unknown"));
22853e4a 1251 ptes[i].changed = 1;
2b6fc908
KZ
1252 break;
1253 }
1254 }
6dbe3af9
KZ
1255}
1256
1257/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
1258 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1259 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1260 * Lubkin Oct. 1991). */
1261
22853e4a 1262static void long2chs(ulong ls, uint *c, uint *h, uint *s) {
6dbe3af9
KZ
1263 int spc = heads * sectors;
1264
1265 *c = ls / spc;
1266 ls = ls % spc;
1267 *h = ls / sectors;
1268 *s = ls % sectors + 1; /* sectors count from 1 */
1269}
1270
22853e4a 1271static void check_consistency(struct partition *p, int partition) {
6dbe3af9
KZ
1272 uint pbc, pbh, pbs; /* physical beginning c, h, s */
1273 uint pec, peh, pes; /* physical ending c, h, s */
1274 uint lbc, lbh, lbs; /* logical beginning c, h, s */
1275 uint lec, leh, les; /* logical ending c, h, s */
1276
1277 if (!heads || !sectors || (partition >= 4))
1278 return; /* do not check extended partitions */
1279
1280/* physical beginning c, h, s */
fd6b7a7f 1281 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
6dbe3af9
KZ
1282 pbh = p->head;
1283 pbs = p->sector & 0x3f;
1284
1285/* physical ending c, h, s */
fd6b7a7f 1286 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
6dbe3af9
KZ
1287 peh = p->end_head;
1288 pes = p->end_sector & 0x3f;
1289
1290/* compute logical beginning (c, h, s) */
2b6fc908 1291 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
6dbe3af9
KZ
1292
1293/* compute logical ending (c, h, s) */
2b6fc908 1294 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
6dbe3af9
KZ
1295
1296/* Same physical / logical beginning? */
1297 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
7eda085c
KZ
1298 printf(_("Partition %d has different physical/logical "
1299 "beginnings (non-Linux?):\n"), partition + 1);
1300 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
1301 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
6dbe3af9
KZ
1302 }
1303
1304/* Same physical / logical ending? */
1305 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
7eda085c
KZ
1306 printf(_("Partition %d has different physical/logical "
1307 "endings:\n"), partition + 1);
1308 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
1309 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
6dbe3af9
KZ
1310 }
1311
726f69e2 1312#if 0
6dbe3af9
KZ
1313/* Beginning on cylinder boundary? */
1314 if (pbh != !pbc || pbs != 1) {
7eda085c
KZ
1315 printf(_("Partition %i does not start on cylinder "
1316 "boundary:\n"), partition + 1);
1317 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
1318 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
6dbe3af9 1319 }
726f69e2 1320#endif
6dbe3af9
KZ
1321
1322/* Ending on cylinder boundary? */
1323 if (peh != (heads - 1) || pes != sectors) {
7eda085c 1324 printf(_("Partition %i does not end on cylinder boundary:\n"),
6dbe3af9 1325 partition + 1);
7eda085c
KZ
1326 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
1327 printf(_("should be (%d, %d, %d)\n"),
6dbe3af9
KZ
1328 pec, heads - 1, sectors);
1329 }
1330}
1331
22853e4a
KZ
1332static void
1333list_disk_geometry(void) {
7eda085c
KZ
1334 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = "
1335 "%s of %d * %d bytes\n\n"), disk_device, heads, sectors,
1336 cylinders, str_units(PLURAL), units_per_sector, sector_size);
5c36a0eb
KZ
1337}
1338
22853e4a
KZ
1339/*
1340 * Check whether partition entries are ordered by their starting positions.
1341 * Return 0 if OK. Return i if partition i should have been earlier.
1342 * Two separate checks: primary and logical partitions.
1343 */
1344static int
1345wrong_p_order(int *prev) {
1346 struct pte *pe;
1347 struct partition *p;
1348 uint last_p_start_pos = 0, p_start_pos;
1349 int i, last_i = 0;
1350
1351 for (i = 0 ; i < partitions; i++) {
1352 if (i == 4) {
1353 last_i = 4;
1354 last_p_start_pos = 0;
1355 }
1356 pe = &ptes[i];
1357 if ((p = pe->part_table)->sys_ind) {
1358 p_start_pos = get_partition_start(pe);
1359
1360 if (last_p_start_pos > p_start_pos) {
1361 if (prev)
1362 *prev = last_i;
1363 return i;
1364 }
1365
1366 last_p_start_pos = p_start_pos;
1367 last_i = i;
1368 }
1369 }
1370 return 0;
1371}
1372
1373static void
1374fix_partition_table_order(void) {
1375 struct pte *pei, *pek, ptebuf;
1376 int i,k;
1377
1378 if(!wrong_p_order(NULL)) {
1379 printf(_("Nothing to do. Ordering is correct already.\n\n"));
1380 return;
1381 }
1382
1383 while ((i = wrong_p_order(&k)) != 0) {
1384 /* partition i should have come earlier, move it */
1385 pei = &ptes[i];
1386 pek = &ptes[k];
1387
1388 if (i < 4) {
1389 /* We have to move data in the MBR */
1390 struct partition *pi, *pk, *pe, pbuf;
1391
1392 pe = pei->ext_pointer;
1393 pei->ext_pointer = pek->ext_pointer;
1394 pek->ext_pointer = pe;
1395
1396 pi = pei->part_table;
1397 pk = pek->part_table;
1398
1399 memmove(&pbuf, pi, sizeof(struct partition));
1400 memmove(pi, pk, sizeof(struct partition));
1401 memmove(pk, &pbuf, sizeof(struct partition));
1402 } else {
1403 /* Only change is change in numbering */
1404 ptebuf = *pei;
1405 *pei = *pek;
1406 *pek = ptebuf;
1407 }
1408 pei->changed = pek->changed = 1;
1409
1410 }
1411}
1412
1413static void
1414list_table(int xtra) {
6dbe3af9
KZ
1415 struct partition *p;
1416 char *type;
2b6fc908
KZ
1417 int i, w;
1418
5c36a0eb 1419 if (sun_label) {
2b6fc908 1420 sun_list_table(xtra);
5c36a0eb
KZ
1421 return;
1422 }
1423
1424 if (sgi_label) {
1425 sgi_list_table(xtra);
1426 return;
1427 }
2b6fc908 1428
22853e4a
KZ
1429 list_disk_geometry();
1430
1431 if (osf_label) {
1432 xbsd_print_disklabel(xtra);
1433 return;
1434 }
1435
5c36a0eb
KZ
1436 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
1437 but if the device name ends in a digit, say /dev/foo1,
1438 then the partition is called /dev/foo1p3. */
22853e4a
KZ
1439 w = strlen(disk_device);
1440 if (w && isdigit(disk_device[w-1]))
1441 w++;
6dbe3af9
KZ
1442 if (w < 5)
1443 w = 5;
7eda085c 1444
7eda085c 1445 printf(_("%*s Boot Start End Blocks Id System\n"),
22853e4a 1446 w+1, _("Device"));
2b6fc908
KZ
1447
1448 for (i = 0 ; i < partitions; i++) {
22853e4a
KZ
1449 struct pte *pe = &ptes[i];
1450
1451 p = pe->part_table;
66ee8158 1452 if (p && p->sys_ind) {
2b6fc908 1453 unsigned int psects = get_nr_sects(p);
5c36a0eb
KZ
1454 unsigned int pblocks = psects;
1455 unsigned int podd = 0;
1456
1457 if (sector_size < 1024) {
1458 pblocks /= (1024 / sector_size);
1459 podd = psects % (1024 / sector_size);
1460 }
1461 if (sector_size > 1024)
1462 pblocks *= (sector_size / 1024);
2b6fc908 1463 printf(
22853e4a
KZ
1464 "%s %c %9ld %9ld %9ld%c %2x %s\n",
1465 partname(disk_device, i+1, w+2),
726f69e2 1466/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
6dbe3af9 1467 ? '*' : '?',
22853e4a
KZ
1468/* start */ (long) cround(get_partition_start(pe)),
1469/* end */ (long) cround(get_partition_start(pe) + psects
2b6fc908 1470 - (psects ? 1 : 0)),
5c36a0eb 1471/* odd flag on end */ (long) pblocks, podd ? '+' : ' ',
726f69e2
KZ
1472/* type id */ p->sys_ind,
1473/* type name */ (type = partition_type(p->sys_ind)) ?
7eda085c 1474 type : _("Unknown"));
6dbe3af9
KZ
1475 check_consistency(p, i);
1476 }
2b6fc908 1477 }
c07ebfa1 1478
22853e4a
KZ
1479 /* Is partition table in disk order? It need not be, but... */
1480 /* partition table entries are not checked for correct order if this
1481 is a sgi, sun or aix labeled disk... */
1482 if (dos_label && wrong_p_order(NULL)) {
1483 printf(_("\nPartition table entries are not in disk order\n"));
1484 }
6dbe3af9
KZ
1485}
1486
22853e4a
KZ
1487static void
1488x_list_table(int extend) {
1489 struct pte *pe;
1490 struct partition *p;
6dbe3af9
KZ
1491 int i;
1492
7eda085c 1493 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
6dbe3af9 1494 disk_device, heads, sectors, cylinders);
eb63b9b8 1495 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
22853e4a
KZ
1496 for (i = 0 ; i < partitions; i++) {
1497 pe = &ptes[i];
1498 p = (extend ? pe->ext_pointer : pe->part_table);
1499 if (p != NULL) {
eb63b9b8 1500 printf("%2d %02x%4d%4d%5d%4d%4d%5d%9d%9d %02x\n",
6dbe3af9
KZ
1501 i + 1, p->boot_ind, p->head,
1502 sector(p->sector),
1503 cylinder(p->sector, p->cyl), p->end_head,
1504 sector(p->end_sector),
1505 cylinder(p->end_sector, p->end_cyl),
2b6fc908 1506 get_start_sect(p), get_nr_sects(p), p->sys_ind);
6dbe3af9
KZ
1507 if (p->sys_ind)
1508 check_consistency(p, i);
1509 }
22853e4a 1510 }
6dbe3af9
KZ
1511}
1512
22853e4a
KZ
1513static void
1514fill_bounds(uint *first, uint *last) {
6dbe3af9 1515 int i;
22853e4a
KZ
1516 struct pte *pe = &ptes[0];
1517 struct partition *p;
6dbe3af9 1518
22853e4a
KZ
1519 for (i = 0; i < partitions; pe++,i++) {
1520 p = pe->part_table;
2b6fc908 1521 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
5c36a0eb 1522 first[i] = 0xffffffff;
6dbe3af9 1523 last[i] = 0;
2b6fc908 1524 } else {
22853e4a 1525 first[i] = get_partition_start(pe);
5c36a0eb 1526 last[i] = first[i] + get_nr_sects(p) - 1;
6dbe3af9 1527 }
2b6fc908 1528 }
6dbe3af9
KZ
1529}
1530
22853e4a
KZ
1531static void
1532check(int n, uint h, uint s, uint c, uint start) {
5c36a0eb 1533 uint total, real_s, real_c;
6dbe3af9
KZ
1534
1535 real_s = sector(s) - 1;
1536 real_c = cylinder(s, c);
1537 total = (real_c * sectors + real_s) * heads + h;
6dbe3af9 1538 if (!total)
7eda085c 1539 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
6dbe3af9
KZ
1540 if (h >= heads)
1541 fprintf(stderr,
7eda085c 1542 _("Partition %d: head %d greater than maximum %d\n"),
6dbe3af9
KZ
1543 n, h + 1, heads);
1544 if (real_s >= sectors)
7eda085c
KZ
1545 fprintf(stderr, _("Partition %d: sector %d greater than "
1546 "maximum %d\n"), n, s, sectors);
6dbe3af9 1547 if (real_c >= cylinders)
7eda085c
KZ
1548 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
1549 "maximum %d\n"), n, real_c + 1, cylinders);
726f69e2 1550 if (cylinders <= 1024 && start != total)
6dbe3af9 1551 fprintf(stderr,
7eda085c
KZ
1552 _("Partition %d: previous sectors %d disagrees with "
1553 "total %d\n"), n, start, total);
6dbe3af9
KZ
1554}
1555
22853e4a
KZ
1556static void
1557verify(void) {
6dbe3af9 1558 int i, j;
5c36a0eb
KZ
1559 uint total = 1;
1560 uint first[partitions], last[partitions];
c07ebfa1 1561 struct partition *p;
6dbe3af9
KZ
1562
1563 if (warn_geometry())
1564 return;
1565
5c36a0eb 1566 if (sun_label) {
2b6fc908 1567 verify_sun();
5c36a0eb
KZ
1568 return;
1569 }
1570
1571 if (sgi_label) {
1572 verify_sgi(1);
1573 return;
1574 }
2b6fc908 1575
5c36a0eb 1576 fill_bounds(first, last);
22853e4a
KZ
1577 for (i = 0; i < partitions; i++) {
1578 struct pte *pe = &ptes[i];
1579
1580 p = pe->part_table;
2b6fc908 1581 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
6dbe3af9 1582 check_consistency(p, i);
22853e4a 1583 if (get_partition_start(pe) < first[i])
7eda085c
KZ
1584 printf(_("Warning: bad start-of-data in "
1585 "partition %d\n"), i + 1);
6dbe3af9
KZ
1586 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
1587 last[i]);
1588 total += last[i] + 1 - first[i];
1589 for (j = 0; j < i; j++)
fd6b7a7f
KZ
1590 if ((first[i] >= first[j] && first[i] <= last[j])
1591 || ((last[i] <= last[j] && last[i] >= first[j]))) {
7eda085c
KZ
1592 printf(_("Warning: partition %d overlaps "
1593 "partition %d.\n"), j + 1, i + 1);
6dbe3af9
KZ
1594 total += first[i] >= first[j] ?
1595 first[i] : first[j];
1596 total -= last[i] <= last[j] ?
1597 last[i] : last[j];
1598 }
1599 }
22853e4a 1600 }
6dbe3af9
KZ
1601
1602 if (extended_offset) {
22853e4a
KZ
1603 struct pte *pex = &ptes[ext_index];
1604 uint e_last = get_start_sect(pex->part_table) +
1605 get_nr_sects(pex->part_table) - 1;
6dbe3af9 1606
22853e4a 1607 for (i = 4; i < partitions; i++) {
6dbe3af9 1608 total++;
22853e4a 1609 p = ptes[i].part_table;
6dbe3af9
KZ
1610 if (!p->sys_ind) {
1611 if (i != 4 || i + 1 < partitions)
7eda085c
KZ
1612 printf(_("Warning: partition %d "
1613 "is empty\n"), i + 1);
6dbe3af9
KZ
1614 }
1615 else if (first[i] < extended_offset ||
1616 last[i] > e_last)
7eda085c
KZ
1617 printf(_("Logical partition %d not entirely in "
1618 "partition %d\n"), i + 1, ext_index + 1);
6dbe3af9
KZ
1619 }
1620 }
1621
1622 if (total > heads * sectors * cylinders)
7eda085c
KZ
1623 printf(_("Total allocated sectors %d greater than the maximum "
1624 "%d\n"), total, heads * sectors * cylinders);
fd6b7a7f 1625 else if ((total = heads * sectors * cylinders - total) != 0)
7eda085c 1626 printf(_("%d unallocated sectors\n"), total);
6dbe3af9
KZ
1627}
1628
22853e4a
KZ
1629static void
1630add_partition(int n, int sys) {
eb63b9b8 1631 char mesg[256]; /* 48 does not suffice in Japanese */
6dbe3af9 1632 int i, read = 0;
22853e4a
KZ
1633 struct partition *p = ptes[n].part_table;
1634 struct partition *q = ptes[ext_index].part_table;
6dbe3af9
KZ
1635 uint start, stop = 0, limit, temp,
1636 first[partitions], last[partitions];
1637
22853e4a 1638 if (p && p->sys_ind) {
7eda085c
KZ
1639 printf(_("Partition %d is already defined. Delete "
1640 "it before re-adding it.\n"), n + 1);
6dbe3af9
KZ
1641 return;
1642 }
5c36a0eb 1643 fill_bounds(first, last);
6dbe3af9
KZ
1644 if (n < 4) {
1645 start = sector_offset;
1646 limit = heads * sectors * cylinders - 1;
1647 if (extended_offset) {
1648 first[ext_index] = extended_offset;
2b6fc908
KZ
1649 last[ext_index] = get_start_sect(q) +
1650 get_nr_sects(q) - 1;
6dbe3af9 1651 }
2b6fc908 1652 } else {
6dbe3af9 1653 start = extended_offset + sector_offset;
2b6fc908 1654 limit = get_start_sect(q) + get_nr_sects(q) - 1;
6dbe3af9 1655 }
7eda085c 1656 if (display_in_cyl_units)
6dbe3af9 1657 for (i = 0; i < partitions; i++)
7eda085c 1658 first[i] = (cround(first[i]) - 1) * units_per_sector;
6dbe3af9 1659
c07ebfa1 1660 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
6dbe3af9
KZ
1661 do {
1662 temp = start;
1663 for (i = 0; i < partitions; i++) {
2b6fc908
KZ
1664 int lastplusoff;
1665
22853e4a 1666 if (start == ptes[i].offset)
6dbe3af9 1667 start += sector_offset;
2b6fc908
KZ
1668 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
1669 if (start >= first[i] && start <= lastplusoff)
1670 start = lastplusoff + 1;
6dbe3af9
KZ
1671 }
1672 if (start > limit)
1673 break;
7eda085c
KZ
1674 if (start >= temp+units_per_sector && read) {
1675 printf(_("Sector %d is already allocated\n"), temp);
2b6fc908 1676 temp = start;
6dbe3af9
KZ
1677 read = 0;
1678 }
1679 if (!read && start == temp) {
1680 uint i;
2b6fc908 1681 i = start;
726f69e2 1682 start = read_int(cround(i), cround(i), cround(limit),
5c36a0eb 1683 0, mesg);
7eda085c
KZ
1684 if (display_in_cyl_units) {
1685 start = (start - 1) * units_per_sector;
6dbe3af9 1686 if (start < i) start = i;
2b6fc908 1687 }
6dbe3af9
KZ
1688 read = 1;
1689 }
1690 } while (start != temp || !read);
7eda085c 1691 if (n > 4) { /* NOT for fifth partition */
22853e4a
KZ
1692 struct pte *pe = &ptes[n];
1693
1694 pe->offset = start - sector_offset;
1695 if (pe->offset == extended_offset) { /* must be corrected */
1696 pe->offset++;
7eda085c
KZ
1697 if (sector_offset == 1)
1698 start++;
1699 }
1700 }
6dbe3af9
KZ
1701
1702 for (i = 0; i < partitions; i++) {
22853e4a
KZ
1703 struct pte *pe = &ptes[i];
1704
1705 if (start < pe->offset && limit >= pe->offset)
1706 limit = pe->offset - 1;
6dbe3af9
KZ
1707 if (start < first[i] && limit >= first[i])
1708 limit = first[i] - 1;
1709 }
1710 if (start > limit) {
7eda085c 1711 printf(_("No free sectors available\n"));
22853e4a 1712 if (n > 4)
6dbe3af9 1713 partitions--;
6dbe3af9
KZ
1714 return;
1715 }
7eda085c
KZ
1716 if (cround(start) == cround(limit)) {
1717 stop = limit;
1718 } else {
c07ebfa1
KZ
1719 snprintf(mesg, sizeof(mesg),
1720 _("Last %s or +size or +sizeM or +sizeK"),
1721 str_units(SINGULAR));
726f69e2 1722 stop = read_int(cround(start), cround(limit), cround(limit),
5c36a0eb 1723 cround(start), mesg);
7eda085c
KZ
1724 if (display_in_cyl_units) {
1725 stop = stop * units_per_sector - 1;
6dbe3af9
KZ
1726 if (stop >limit)
1727 stop = limit;
1728 }
1729 }
1730
22853e4a 1731 set_partition(n, p, start, stop, sys, ptes[n].offset);
6dbe3af9 1732
2b6fc908 1733 if (IS_EXTENDED (sys)) {
22853e4a
KZ
1734 struct pte *pe4 = &ptes[4];
1735 struct pte *pen = &ptes[n];
1736
6dbe3af9 1737 ext_index = n;
22853e4a
KZ
1738 pen->ext_pointer = p;
1739 pe4->offset = extended_offset = start;
1740 if (!(pe4->sectorbuffer = calloc(1, sector_size)))
6dbe3af9 1741 fatal(out_of_memory);
22853e4a
KZ
1742 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
1743 pe4->ext_pointer = pe4->part_table + 1;
1744 pe4->changed = 1;
6dbe3af9 1745 partitions = 5;
7eda085c 1746 } else {
6dbe3af9 1747 if (n > 4)
22853e4a
KZ
1748 set_partition(n - 1, ptes[n-1].ext_pointer,
1749 ptes[n].offset, stop, EXTENDED,
6dbe3af9
KZ
1750 extended_offset);
1751#if 0
2b6fc908 1752 if ((limit = get_nr_sects(p)) & 1)
7eda085c
KZ
1753 printf(_("Warning: partition %d has an odd "
1754 "number of sectors.\n"), n + 1);
6dbe3af9
KZ
1755#endif
1756 }
1757}
1758
22853e4a
KZ
1759static void
1760add_logical(void) {
1761 if (partitions > 5 || ptes[4].part_table->sys_ind) {
1762 struct pte *pe = &ptes[partitions];
1763
1764 if (!(pe->sectorbuffer = calloc(1, sector_size)))
6dbe3af9 1765 fatal(out_of_memory);
22853e4a
KZ
1766 pe->part_table = pt_offset(pe->sectorbuffer, 0);
1767 pe->ext_pointer = pe->part_table + 1;
1768 pe->offset = 0;
1769 pe->changed = 1;
6dbe3af9
KZ
1770 partitions++;
1771 }
1772 add_partition(partitions - 1, LINUX_NATIVE);
1773}
1774
22853e4a
KZ
1775static void
1776new_partition(void) {
6dbe3af9
KZ
1777 int i, free_primary = 0;
1778
1779 if (warn_geometry())
1780 return;
2b6fc908 1781
5c36a0eb 1782 if (sun_label) {
2b6fc908 1783 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5c36a0eb
KZ
1784 return;
1785 }
1786
1787 if (sgi_label) {
1788 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
1789 return;
1790 }
2b6fc908 1791
6dbe3af9 1792 if (partitions >= MAXIMUM_PARTS) {
7eda085c 1793 printf(_("The maximum number of partitions has been created\n"));
6dbe3af9
KZ
1794 return;
1795 }
1796
1797 for (i = 0; i < 4; i++)
22853e4a 1798 free_primary += !ptes[i].part_table->sys_ind;
5c36a0eb 1799 if (!free_primary) {
6dbe3af9
KZ
1800 if (extended_offset)
1801 add_logical();
1802 else
7eda085c 1803 printf(_("You must delete some partition and add "
c07ebfa1 1804 "an extended partition first\n"));
5c36a0eb 1805 } else {
6dbe3af9 1806 char c, line[LINE_LENGTH];
c07ebfa1
KZ
1807 snprintf(line, sizeof(line),
1808 _("Command action\n %s\n p primary "
1809 "partition (1-4)\n"), extended_offset ?
1810 _("l logical (5 or over)") : _("e extended"));
1811 while (1) {
6dbe3af9
KZ
1812 if ((c = tolower(read_char(line))) == 'p') {
1813 add_partition(get_partition(0, 4),
c07ebfa1 1814 LINUX_NATIVE);
6dbe3af9
KZ
1815 return;
1816 }
1817 else if (c == 'l' && extended_offset) {
1818 add_logical();
1819 return;
1820 }
1821 else if (c == 'e' && !extended_offset) {
1822 add_partition(get_partition(0, 4),
c07ebfa1 1823 EXTENDED);
6dbe3af9
KZ
1824 return;
1825 }
726f69e2 1826 else
7eda085c 1827 printf(_("Invalid partition number "
c07ebfa1
KZ
1828 "for type `%c'\n"), c);
1829 }
6dbe3af9
KZ
1830 }
1831}
1832
22853e4a
KZ
1833static void
1834write_table(void) {
eb63b9b8 1835 int i;
6dbe3af9 1836
22853e4a
KZ
1837 if (dos_label) {
1838 for (i=0; i<3; i++)
1839 if(ptes[i].changed)
1840 ptes[3].changed = 1;
1841 for (i = 3; i < partitions; i++) {
1842 struct pte *pe = &ptes[i];
1843
1844 if (pe->changed) {
1845 write_part_table_flag(pe->sectorbuffer);
1846 write_sector(fd, pe->offset, pe->sectorbuffer);
1847 }
2b6fc908 1848 }
5c36a0eb 1849 } else if (sgi_label) {
22853e4a
KZ
1850 /* no test on change? the printf below might be mistaken */
1851 sgi_write_table();
5c36a0eb 1852 } else if (sun_label) {
22853e4a
KZ
1853 int needw = 0;
1854
1855 for (i=0; i<8; i++)
1856 if(ptes[i].changed)
1857 needw = 1;
1858 if (needw)
1859 sun_write_table();
6dbe3af9
KZ
1860 }
1861
7eda085c 1862 printf(_("The partition table has been altered!\n\n"));
eb63b9b8
KZ
1863 reread_partition_table(1);
1864}
1865
1866void
1867reread_partition_table(int leave) {
1868 int error = 0;
1869 int i;
6dbe3af9 1870
7eda085c 1871 printf(_("Calling ioctl() to re-read partition table.\n"));
6dbe3af9
KZ
1872 sync();
1873 sleep(2);
fd6b7a7f 1874 if ((i = ioctl(fd, BLKRRPART)) != 0) {
726f69e2
KZ
1875 error = errno;
1876 } else {
1877 /* some kernel versions (1.2.x) seem to have trouble
1878 rereading the partition table, but if asked to do it
1879 twice, the second time works. - biro@yggdrasil.com */
1880 sync();
1881 sleep(2);
fd6b7a7f 1882 if((i = ioctl(fd, BLKRRPART)) != 0)
726f69e2
KZ
1883 error = errno;
1884 }
1885
726f69e2 1886 if (i < 0)
7eda085c
KZ
1887 printf(_("Re-read table failed with error %d: %s.\nReboot your "
1888 "system to ensure the partition table is updated.\n"),
6dbe3af9
KZ
1889 error, strerror(error));
1890
5c36a0eb 1891 if (!sun_label && !sgi_label)
2b6fc908 1892 printf(
7eda085c 1893 _("\nWARNING: If you have created or modified any DOS 6.x\n"
6dbe3af9 1894 "partitions, please see the fdisk manual page for additional\n"
7eda085c 1895 "information.\n"));
6dbe3af9 1896
eb63b9b8
KZ
1897 if (leave) {
1898 close(fd);
1899
1900 printf(_("Syncing disks.\n"));
1901 sync();
1902 sleep(4); /* for sync() */
1903 exit(!!i);
1904 }
6dbe3af9
KZ
1905}
1906
1907#define MAX_PER_LINE 16
22853e4a
KZ
1908static void
1909print_buffer(char pbuffer[]) {
6dbe3af9
KZ
1910 int i,
1911 l;
1912
5c36a0eb 1913 for (i = 0, l = 0; i < sector_size; i++, l++) {
6dbe3af9
KZ
1914 if (l == 0)
1915 printf("0x%03X:", i);
22853e4a 1916 printf(" %02X", (unsigned char) pbuffer[i]);
6dbe3af9
KZ
1917 if (l == MAX_PER_LINE - 1) {
1918 printf("\n");
1919 l = -1;
1920 }
1921 }
1922 if (l > 0)
1923 printf("\n");
1924 printf("\n");
1925}
1926
22853e4a
KZ
1927static void
1928print_raw(void) {
6dbe3af9
KZ
1929 int i;
1930
7eda085c 1931 printf(_("Device: %s\n"), disk_device);
5c36a0eb 1932 if (sun_label || sgi_label)
22853e4a 1933 print_buffer(MBRbuffer);
2b6fc908 1934 else for (i = 3; i < partitions; i++)
22853e4a 1935 print_buffer(ptes[i].sectorbuffer);
6dbe3af9
KZ
1936}
1937
22853e4a
KZ
1938static void
1939move_begin(int i) {
1940 struct pte *pe = &ptes[i];
1941 struct partition *p = pe->part_table;
6dbe3af9
KZ
1942 uint new, first;
1943
1944 if (warn_geometry())
1945 return;
2b6fc908 1946 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
7eda085c 1947 printf(_("Partition %d has no data area\n"), i + 1);
6dbe3af9
KZ
1948 return;
1949 }
22853e4a
KZ
1950 first = get_partition_start(pe);
1951 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
1952 _("New beginning of data")) - pe->offset;
6dbe3af9 1953
2b6fc908
KZ
1954 if (new != get_nr_sects(p)) {
1955 first = get_nr_sects(p) + get_start_sect(p) - new;
1956 set_nr_sects(p, first);
1957 set_start_sect(p, new);
22853e4a 1958 pe->changed = 1;
6dbe3af9
KZ
1959 }
1960}
1961
22853e4a
KZ
1962static void
1963xselect(void) {
1964 char c;
1965
6dbe3af9
KZ
1966 while(1) {
1967 putchar('\n');
22853e4a
KZ
1968 c = tolower(read_char(_("Expert command (m for help): ")));
1969 switch (c) {
2b6fc908
KZ
1970 case 'a':
1971 if (sun_label)
1972 sun_set_alt_cyl();
1973 break;
2b6fc908 1974 case 'b':
22853e4a 1975 if (dos_label)
2b6fc908
KZ
1976 move_begin(get_partition(0, partitions));
1977 break;
1978 case 'c':
22853e4a
KZ
1979 user_cylinders = cylinders =
1980 read_int(1, cylinders, 131071, 0,
1981 _("Number of cylinders"));
2b6fc908
KZ
1982 if (sun_label)
1983 sun_set_ncyl(cylinders);
22853e4a
KZ
1984 if (dos_label)
1985 warn_cylinders();
2b6fc908
KZ
1986 break;
1987 case 'd':
1988 print_raw();
1989 break;
1990 case 'e':
5c36a0eb
KZ
1991 if (sgi_label)
1992 sgi_set_xcyl();
1993 else if (sun_label)
2b6fc908 1994 sun_set_xcyl();
22853e4a 1995 else if (dos_label)
5c36a0eb
KZ
1996 x_list_table(1);
1997 break;
22853e4a
KZ
1998 case 'f':
1999 if(dos_label)
2000 fix_partition_table_order();
2001 break;
5c36a0eb
KZ
2002 case 'g':
2003 create_sgilabel();
2b6fc908
KZ
2004 break;
2005 case 'h':
22853e4a 2006 user_heads = heads = read_int(1, heads, 256, 0,
7eda085c 2007 _("Number of heads"));
2b6fc908
KZ
2008 update_units();
2009 break;
2b6fc908
KZ
2010 case 'i':
2011 if (sun_label)
2012 sun_set_ilfact();
2013 break;
2014 case 'o':
2015 if (sun_label)
2016 sun_set_rspeed();
2017 break;
2b6fc908 2018 case 'p':
2b6fc908
KZ
2019 if (sun_label)
2020 list_table(1);
2021 else
2b6fc908
KZ
2022 x_list_table(0);
2023 break;
2024 case 'q':
2025 close(fd);
7eda085c 2026 printf("\n");
2b6fc908
KZ
2027 exit(0);
2028 case 'r':
2029 return;
2030 case 's':
22853e4a 2031 user_sectors = sectors = read_int(1, sectors, 63, 0,
7eda085c 2032 _("Number of sectors"));
2b6fc908
KZ
2033 if (dos_compatible_flag) {
2034 sector_offset = sectors;
7eda085c 2035 fprintf(stderr, _("Warning: setting "
2b6fc908 2036 "sector offset for DOS "
7eda085c 2037 "compatiblity\n"));
2b6fc908
KZ
2038 }
2039 update_units();
2040 break;
2041 case 'v':
2042 verify();
2043 break;
2044 case 'w':
2045 write_table(); /* does not return */
2046 break;
2b6fc908
KZ
2047 case 'y':
2048 if (sun_label)
2049 sun_set_pcylcount();
2050 break;
2b6fc908
KZ
2051 default:
2052 xmenu();
6dbe3af9
KZ
2053 }
2054 }
2055}
2056
22853e4a 2057static int
2b6fc908
KZ
2058is_ide_cdrom(char *device) {
2059 /* No device was given explicitly, and we are trying some
2060 likely things. But opening /dev/hdc may produce errors like
2061 "hdc: tray open or drive not ready"
2062 if it happens to be a CD-ROM drive. It even happens that
2063 the process hangs on the attempt to read a music CD.
2064 So try to be careful. This only works since 2.1.73. */
2065
2066 FILE *procf;
2067 char buf[100];
2068 struct stat statbuf;
2069
5c36a0eb
KZ
2070 if (strncmp("/dev/hd", device, 7))
2071 return 0;
c07ebfa1 2072 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2b6fc908
KZ
2073 procf = fopen(buf, "r");
2074 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2075 return !strncmp(buf, "cdrom", 5);
2076
2077 /* Now when this proc file does not exist, skip the
2078 device when it is read-only. */
2079 if (stat(device, &statbuf) == 0)
2080 return (statbuf.st_mode & 0222) == 0;
2081
2082 return 0;
2083}
2084
22853e4a
KZ
2085static void
2086try(char *device, int user_specified) {
6dbe3af9 2087 disk_device = device;
c07ebfa1
KZ
2088 if (setjmp(listingbuf))
2089 return;
2090 if (!user_specified)
2091 if (is_ide_cdrom(device))
2092 return;
2093 if ((fd = open(disk_device, type_open)) >= 0) {
2094 if (get_boot(try_only) < 0) {
2095 list_disk_geometry();
2096 if (aix_label)
2b6fc908 2097 return;
c07ebfa1
KZ
2098 if (btrydev(device) < 0)
2099 fprintf(stderr,
2100 _("Disk %s doesn't contain a valid "
2101 "partition table\n"), device);
2102 close(fd);
fd6b7a7f 2103 } else {
c07ebfa1
KZ
2104 close(fd);
2105 list_table(0);
2106 if (!sun_label && partitions > 4)
2107 delete_partition(ext_index);
2108 }
2109 } else {
2110 /* Ignore other errors, since we try IDE
2111 and SCSI hard disks which may not be
2112 installed on the system. */
2113 if(errno == EACCES) {
2114 fprintf(stderr, _("Cannot open %s\n"), device);
2115 return;
fd6b7a7f
KZ
2116 }
2117 }
6dbe3af9
KZ
2118}
2119
eb63b9b8
KZ
2120/* for fdisk -l: try all things in /proc/partitions
2121 that look like a partition name (do not end in a digit) */
22853e4a
KZ
2122static void
2123tryprocpt(void) {
eb63b9b8
KZ
2124 FILE *procpt;
2125 char line[100], ptname[100], devname[120], *s;
2126 int ma, mi, sz;
2127
2128 procpt = fopen(PROC_PARTITIONS, "r");
2129 if (procpt == NULL) {
2130 fprintf(stderr, _("cannot open %s\n"), PROC_PARTITIONS);
2131 return;
2132 }
2133
2134 while (fgets(line, sizeof(line), procpt)) {
c07ebfa1 2135 if (sscanf (line, " %d %d %d %[^\n ]",
eb63b9b8
KZ
2136 &ma, &mi, &sz, ptname) != 4)
2137 continue;
2138 for(s = ptname; *s; s++);
2139 if (isdigit(s[-1]))
2140 continue;
c07ebfa1 2141 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
66ee8158 2142 try(devname, 0);
eb63b9b8
KZ
2143 }
2144}
2145
22853e4a
KZ
2146static void
2147dummy(int *kk) {}
7eda085c 2148
22853e4a
KZ
2149static void
2150unknown_command(int c) {
2151 printf(_("%c: unknown command\n"), c);
7eda085c
KZ
2152}
2153
5c36a0eb 2154int
eb63b9b8 2155main(int argc, char **argv) {
7eda085c 2156 int j, c;
2b6fc908 2157 int optl = 0, opts = 0;
2b6fc908 2158
7eda085c
KZ
2159 setlocale(LC_ALL, "");
2160 bindtextdomain(PACKAGE, LOCALEDIR);
2161 textdomain(PACKAGE);
2b6fc908
KZ
2162
2163 /*
2164 * Calls:
2165 * fdisk -v
7eda085c 2166 * fdisk -l [-b sectorsize] [-u] device ...
2b6fc908 2167 * fdisk -s [partition] ...
7eda085c 2168 * fdisk [-b sectorsize] [-u] device
2b6fc908 2169 */
22853e4a 2170 while ((c = getopt(argc, argv, "b:lsuvV")) != EOF) {
2b6fc908
KZ
2171 switch (c) {
2172 case 'b':
7eda085c
KZ
2173 /* ugly: this sector size is really per device,
2174 so cannot be combined with multiple disks */
5c36a0eb
KZ
2175 sector_size = atoi(optarg);
2176 if (sector_size != 512 && sector_size != 1024 &&
2177 sector_size != 2048)
2178 fatal(usage);
2179 sector_offset = 2;
7eda085c 2180 user_set_sector_size = 1;
2b6fc908
KZ
2181 break;
2182 case 'l':
2183 optl = 1;
2184 break;
2185 case 's':
2186 opts = 1;
2187 break;
2188 case 'u':
7eda085c 2189 display_in_cyl_units = 0;
2b6fc908 2190 break;
22853e4a 2191 case 'V':
2b6fc908 2192 case 'v':
5c36a0eb 2193 printf("fdisk v" UTIL_LINUX_VERSION "\n");
2b6fc908
KZ
2194 exit(0);
2195 default:
2196 fatal(usage);
2197 }
6dbe3af9 2198 }
2b6fc908 2199
7eda085c
KZ
2200#if 0
2201 printf(_("This kernel finds the sector size itself - -b option ignored\n"));
2202#else
2203 if (user_set_sector_size && argc-optind != 1)
2204 printf(_("Warning: the -b (set sector size) option should"
2205 " be used with one specified device\n"));
2206#endif
2207
2b6fc908 2208 if (optl) {
2b6fc908
KZ
2209 nowarn = 1;
2210 type_open = O_RDONLY;
2211 if (argc > optind) {
2212 int k;
2213 /* avoid gcc warning:
2214 variable `k' might be clobbered by `longjmp' */
2215 dummy(&k);
eb63b9b8 2216 listing = 1;
2b6fc908
KZ
2217 for(k=optind; k<argc; k++)
2218 try(argv[k], 1);
2219 } else {
7eda085c 2220 /* we no longer have default device names */
eb63b9b8
KZ
2221 /* but, we can use /proc/partitions instead */
2222 tryprocpt();
2b6fc908
KZ
2223 }
2224 exit(0);
2225 }
2226
2227 if (opts) {
7eda085c
KZ
2228 long size;
2229
2b6fc908 2230 nowarn = 1;
2b6fc908
KZ
2231 type_open = O_RDONLY;
2232
2233 opts = argc - optind;
2234 if (opts <= 0)
2235 fatal(usage);
2236
2237 for (j = optind; j < argc; j++) {
7eda085c 2238 disk_device = argv[j];
2b6fc908
KZ
2239 if ((fd = open(disk_device, type_open)) < 0)
2240 fatal(unable_to_open);
7eda085c
KZ
2241 if (ioctl(fd, BLKGETSIZE, &size))
2242 fatal(ioctl_error);
2b6fc908 2243 close(fd);
2b6fc908 2244 if (opts == 1)
7eda085c 2245 printf("%ld\n", size/2);
2b6fc908 2246 else
7eda085c 2247 printf("%s: %ld\n", argv[j], size/2);
6dbe3af9 2248 }
2b6fc908 2249 exit(0);
6dbe3af9 2250 }
6dbe3af9 2251
2b6fc908
KZ
2252 if (argc-optind == 1)
2253 disk_device = argv[optind];
2254 else if (argc-optind != 0)
2255 fatal(usage);
7eda085c
KZ
2256 else
2257 fatal(usage2);
2258
2b6fc908 2259 get_boot(fdisk);
66ee8158
KZ
2260 if (aix_label)
2261 exit(0);
6dbe3af9 2262
22853e4a
KZ
2263#ifdef __alpha__
2264 /* On alpha, if we detect a disklabel, go directly to
2265 disklabel mode (typically you'll be switching from DOS
2266 partition tables to disklabels, not the other way around)
2267 - dhuggins@linuxcare.com */
2268 if (osf_label) {
2269 printf(_("Detected an OSF/1 disklabel on %s, entering disklabel mode.\n"
2270 "To return to DOS partition table mode, use the 'r' command.\n"),
2271 disk_device);
2272 bselect();
2273 }
2274#endif
2275
6dbe3af9
KZ
2276 while (1) {
2277 putchar('\n');
22853e4a
KZ
2278 c = tolower(read_char(_("Command (m for help): ")));
2279 switch (c) {
2b6fc908 2280 case 'a':
22853e4a
KZ
2281 if (dos_label)
2282 toggle_active(get_partition(1, partitions));
2283 else if (sun_label)
2b6fc908
KZ
2284 toggle_sunflags(get_partition(1, partitions),
2285 0x01);
22853e4a
KZ
2286 else if (sgi_label)
2287 sgi_set_bootpartition(
2288 get_partition(1, partitions));
2b6fc908 2289 else
22853e4a 2290 unknown_command(c);
2b6fc908
KZ
2291 break;
2292 case 'b':
5c36a0eb 2293 if (sgi_label) {
7eda085c 2294 printf(_("\nThe current boot file is: %s\n"),
5c36a0eb 2295 sgi_get_bootfile());
7eda085c
KZ
2296 if (read_chars(_("Please enter the name of the "
2297 "new boot file: ")) == '\n')
2298 printf(_("Boot file unchanged\n"));
5c36a0eb
KZ
2299 else
2300 sgi_set_bootfile(line_ptr);
2301 } else
2302 bselect();
2b6fc908
KZ
2303 break;
2304 case 'c':
22853e4a
KZ
2305 if (dos_label)
2306 toggle_dos_compatibility_flag();
2307 else if (sun_label)
2b6fc908
KZ
2308 toggle_sunflags(get_partition(1, partitions),
2309 0x10);
22853e4a
KZ
2310 else if (sgi_label)
2311 sgi_set_swappartition(
5c36a0eb 2312 get_partition(1, partitions));
22853e4a
KZ
2313 else
2314 unknown_command(c);
2b6fc908
KZ
2315 break;
2316 case 'd':
2317 delete_partition(
2318 get_partition(1, partitions));
2319 break;
5c36a0eb
KZ
2320 case 'i':
2321 if (sgi_label)
2322 create_sgiinfo();
2b6fc908 2323 else
22853e4a 2324 unknown_command(c);
5c36a0eb
KZ
2325 case 'l':
2326 list_types(get_sys_types());
2b6fc908 2327 break;
22853e4a
KZ
2328 case 'm':
2329 menu();
2330 break;
2b6fc908
KZ
2331 case 'n':
2332 new_partition();
2333 break;
2334 case 'o':
2335 create_doslabel();
2336 break;
2337 case 'p':
2338 list_table(0);
2339 break;
2340 case 'q':
2341 close(fd);
7eda085c 2342 printf("\n");
2b6fc908 2343 exit(0);
2b6fc908
KZ
2344 case 's':
2345 create_sunlabel();
2346 break;
2b6fc908
KZ
2347 case 't':
2348 change_sysid();
2349 break;
2350 case 'u':
2351 change_units();
2352 break;
2353 case 'v':
2354 verify();
2355 break;
2356 case 'w':
2357 write_table(); /* does not return */
2358 break;
2359 case 'x':
22853e4a 2360 if(sgi_label) {
5c36a0eb 2361 fprintf(stderr,
7eda085c
KZ
2362 _("\n\tSorry, no experts menu for SGI "
2363 "partition tables available.\n\n"));
5c36a0eb
KZ
2364 } else
2365 xselect();
2b6fc908 2366 break;
22853e4a
KZ
2367 default:
2368 unknown_command(c);
2369 menu();
6dbe3af9
KZ
2370 }
2371 }
5c36a0eb 2372 return 0;
6dbe3af9 2373}